Vector2 object in SDK?

0 favourites
  • 5 posts
From the Asset Store
This is a single chapter from the "Construct Starter Kit Collection". It is the Student Workbook for its Workshop.
  • The discussion in short: Can we have a set of Vector2 math functions in Construct 2 available for any plugin to use?

    For certain plugins and behaviors, having a vector math library is extremely useful as it can often cut down the amount of challenging, error-prone calculations by at least half. We see this in the Physics behavior, where Box2D uses b2Vec2 extensively and has a thorough selection of vector math functions. I found it surprising that there is really no useful set of 2D Vector operations provided as part of the Construct 2 framework for all plugins to use. It seems that currently, the only option as a plugin developer is to include your own Vector2 definition and set of methods, which is obviously inefficient and wasteful if more than one plugin needs vector support.

    I understand Scirra's reasoning for avoiding pervasive use of a Vector2 object (primarily because it lends itself easily to careless object creation and GC problems). I have read these articles concerning Vector2's and garbage collection (the last two are written by Ashley):

    Efficient JavaScript Vector Math - media.tojicode.com/sfjs-vectors

    scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript

    netmagazine.com/tutorials/make-your-javascript-apps-smoother

    The key takeaway I get from these articles is that careless instantiation of objects is the main problem. It sounds like the overhead of accessing properties or indexing arrays (ie. v.x or v[0] as opposed to vx) or using methods instead of inlining calculations is insignificant and generally acceptable for the increased code readability.

    To address the risk of garbage, I think a simple comment on the Vector2 object linking to one of Ashley's above articles would help a lot. Also, the methods should all be designed with out parameters so that the user needs to instantiate the result objects ahead of time, and will hopefully do so smartly. An example of what some of these functions might look like:

    Vec2.addV = function (a, b, out)
    {
         out.x = a.x + b.x;
         out.y = a.y + b.y;
         return out;
    };
    //Linearly interpolate between a (when s=0) and b (when s=1)
    Vec2.lerp = function (a, b, s, out)
    {
         out.x = a.x + s * (b.x - a.x);
         out.y = a.y + s * (b.y - a.y);
         return out;
    };

    The return out; is optional (and I don't know if it affects performance over returning nothing), but it allows you to nest operations instead of being limited to one operation per line. Ex:

    //This code only does one math operation per line
    Vec2.addV(a, obj, originToA);
    Vec2.subV(originToA, origin, originToA);
    
    //But you have the option of compacting into a single line for the same result
    Vec2.subV(Vec2.addV(a, obj, originToA), origin, originToA);

    Regarding the option of using typed arrays over objects (see 1st article), I think it's still best to use plain objects with x and y properties. Using objects and static methods is actually nice; in the code above, obj is a Sprite object, but it can still be used as if it were a Vec2 because it has numeric x and y properties.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Are you talking about the editor or the runtime? In the editor, generally I don't think you don't need to do anything complicated so such a library isn't so useful. In the runtime, it is a terrible idea to use them for GC reasons. Box2D is horrendous for causing big GC pauses, precisely because it uses b2Vec2. Your proposed solution does not really solve the problem because you still need to have 100% perfect recycling of the objects you pass to those functions, or you create GC problems still. It is very difficult to write code that does this, because you need to invent a clear system of ownership and make sure you get your "free" calls in exactly the right places, which is error-prone. So it really is better just to avoid them completely.

    If you really, really need it, you can probably find your own JS math library and integrate it. But you should be extremely careful not to slow down the games using your plugin.

  • Yeah, sorry, I was referring to having a Vector2 class during runtime.

    Currently, the way I plan to use my own Vector2 objects (I'm still in the prototyping/debugging stage) is that I create about 6 local Vector2 objects once and use them as temporary variables. Initialization would look like this:

    instanceProto.onCreate = function ()
    {
      this.tempVec0 = new Vector2();
      this.tempVec1 = new Vector2();
      //or if I need a large number of temporary vectors
      this.tempVec = this.CreateArrayOfVector2(numTempVectors);
    }

    And then later, I might rename my temporary vectors in methods for clarity, but I don't actually create any new vectors during a frame. I know this is a very basic resource pooling method, but it's fine for my current needs:

    instanceProto.doSomething = function ()
    {
      var posn = this.tempVec[0];
      var norm = this.tempVec[1];
      var aToB = this.tempVec[2];
      ...
      posn.x = someObj.GetX();
      posn.y = someObj.GetY();
      ...
    }

    As far as I understand, this should not add any extra garbage overhead per frame. Please correct me if I am mistaken! It seems that it should be pretty simple not to create more garbage as long as you're disciplined enough to never create a new object after initializing your object/plugin.

    Is your opinion basically "If people have sharp knives, they're likely to hurt themselves and others, so I don't want to make it easy for anyone to have a sharp knife"? I think that's reasonable, but still, if you don't provide a framework for those who do want the sharp knives, they might not do a good job at making them themselves. Certainly, the Vector class I wrote years ago in school wouldn't have been acceptable.

    I see that in Plugin Settings (https://www.scirra.com/manual/18/plugin-settings) there is a "dependency" property for including additional files in runtime. Would it be reasonable to provide a Vector2 library, but force people to figure out how to include it in their plugin. At the top of Vector2.js you could have a big disclaimer about how misuse of vectors can ruin performance.

  • Well, my policy is "don't use sharp knives because they can hurt you, but if you really need one you can go and get one yourself". There are already lots of excellent JS libraries out there and I don't see why we should reinvent the wheel - you can just go and integrate one yourself, if you're aware of the possible shortcomings of the library for games.

    If your code really is that simple, it should be fine since it appears to avoid allocations. But then if that's all the code is, I'd just use x/y values myself to avoid dependency on a whole library.

    You can use the dependency field, but it can work better just pasting an entire JS library to the top of the runtime.js file. The Physics behavior has the whole Box2D library pasted in to the top.

  • Okay, that's fair. I wasn't suggesting that we reinvent the wheel and make our own Vector2 library, I just felt it was peculiar that there wasn't already some library that plugins could share among one another.

    I did notice that the Physics behavior had all of Box2D in runtime.js instead of using the dependency field and thought that that was strange. What benefit do you get out of having all of your source in one file?

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)