lots of bugs / warnings c2runtime

0 favourites
  • ok, since i've cleaned most of the stuff i'll start in a few days with optimizations and microopts, hopefully these are taken care of if nothing at least i've done it for my pleasure, regardless if ashley finds them usefull / useless.

  • here's a first test i've done.. function "next power of two" - found in common_prelude.js

    results here:


    old code:

    cr.nextHighestPowerOfTwo = function (x) {
    	    for (var i = 1; i < 32; i <<= 1) {
    	        x = x | x >> i;
    	    return x + 1;
    new code:
    [code:d6luuvun]	cr.nextHighestPowerOfTwo = function (x) {
    		x |= x >> 1;
    		x |= x >> 2;
    		x |= x >> 4;
    		x |= x >> 8;
    		x |= x >> 16;
    		return x+1;
  • next up, improvement in collision detection:


    since i've got a project that achieves around 60 000 collision checks per second, these values seem pretty good for improvement. it changes the section intersect code. i've noticed that it can be further improved by moving the code to gpu, but that's another pair of glasses. in preview i noticed around 3-4% less cpu usage when high collision checks hits in. found in common_prelude.js

    old code:

    // Segment intersection
    	cr.segments_intersect = function(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)
    		var max_ax, min_ax, max_ay, min_ay, max_bx, min_bx, max_by, min_by;
    		// Long-hand code since this is a performance hotspot and this type of
    		// code minimises the number of conditional tests necessary.
    		if (a1x < a2x)
    			min_ax = a1x;
    			max_ax = a2x;
    			min_ax = a2x;
    			max_ax = a1x;
    		if (b1x < b2x)
    			min_bx = b1x;
    			max_bx = b2x;
    			min_bx = b2x;
    			max_bx = b1x;
    		if (max_ax < min_bx || min_ax > max_bx)
    			return false;
    		if (a1y < a2y)
    			min_ay = a1y;
    			max_ay = a2y;
    			min_ay = a2y;
    			max_ay = a1y;
    		if (b1y < b2y)
    			min_by = b1y;
    			max_by = b2y;
    			min_by = b2y;
    			max_by = b1y;
    		if (max_ay < min_by || min_ay > max_by)
    			return false;
    		var dpx = b1x - a1x + b2x - a2x;
    		var dpy = b1y - a1y + b2y - a2y;
    		var qax = a2x - a1x;
    		var qay = a2y - a1y;
    		var qbx = b2x - b1x;
    		var qby = b2y - b1y;
    		var d = cr.abs(qay * qbx - qby * qax);
    		var la = qbx * dpy - qby * dpx;
    		if (cr.abs(la) > d)
    			return false;
    		var lb = qax * dpy - qay * dpx;
    		return cr.abs(lb) <= d;
    new code:
    [code:2tumiohd]// Segment intersection	
    	cr.segments_intersect = function (a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) {
    	var s02_x, s02_y, s10_x, s10_y, s32_x, s32_y, s_numer, t_numer, denom, t;
    	s10_x = a2x - a1x;
    	s10_y = a2y - a1y;
    	s32_x = b2x - b1x;
    	s32_y = b2y - b1y;
        denom = s10_x * s32_y - s32_x * s10_y;
        if (denom == 0)
    		return false;
        var denomPositive = denom > 0;
        s02_x = a1x - b1x;
        s02_y = a1y - b1y;
        s_numer = s10_x * s02_y - s10_y * s02_x;
        if ((s_numer < 0) == denomPositive)
            return false; 	
        t_numer = s32_x * s02_y - s32_y * s02_x;
        if ((t_numer < 0) == denomPositive)
            return false; 
        if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive))
            return false; 
        return true;
  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • here comes a big one, which i didn't use in ingame engine (i did but reverted change) but Ashley might describe where the problem is and why:

    so there's this function that tests if a point is in quad (Quad.prototype.contains_pt = function (x, y)), so here's it's code:

    Quad.prototype.contains_pt = function (x, y)
    		var tlx = this.tlx;
    		var tly = this.tly;
    		var v0x = trx - tlx;
    		var v0y = try_ - tly;
    		var v1x = brx - tlx;
    		var v1y = bry - tly;
    		var v2x = x - tlx;
    		var v2y = y - tly;
    		var dot00 = v0x * v0x + v0y * v0y;
    		var dot01 = v0x * v1x + v0y * v1y;
    		var dot02 = v0x * v2x + v0y * v2y;
    		var dot11 = v1x * v1x + v1y * v1y;
    		var dot12 = v1x * v2x + v1y * v2y;
    		var invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01);
    		var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
    		var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
    		if ((u >= 0.0) && (v > 0.0) && (u + v < 1))
    			return true;
    		v0x = blx - tlx;
    		v0y = bly - tly;
    		dot00 = v0x * v0x + v0y * v0y;
    		dot01 = v0x * v1x + v0y * v1y;
    		dot02 = v0x * v2x + v0y * v2y;
    		invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01);
    		u = (dot11 * dot02 - dot01 * dot12) * invDenom;
    		v = (dot00 * dot12 - dot01 * dot02) * invDenom;
    						// Point is in second triangle
    		return (u >= 0.0) && (v > 0.0) && (u + v < 1);
    so i've wanted to upgrade this, and after checking manual and doing some work of my own, i've noticed that every quad is split into 2 triangles and then the point is checked in each, if found in first return true, else check other and return true if there or it's false.  it's being done with some mad math. 
    so i went to see what is the most performant way to do it, and here's what i got:
    [code:ysujrfy2]		if((((this.try_ - this.tly) * (x - this.tlx) - (this.trx - this.tlx) * (y - this.tly)) | ((this.bry - this.try_) * (x - this.trx) - (this.brx - this.trx) * (y - this.try_)) | ((this.tly - this.bry) * (x - this.brx) - (this.tlx - this.brx) * (y - this.bry))) >= 0)
    						return true;
    						if((((this.bry - this.tly) * (x-this.tlx) - (this.brx - this.tlx) * (y - this.tly)) | ((this.bly - this.bry) * (x - this.brx) - (this.blx - this.brx) * (y- this.bry)) | ((this.tly - this.bly) * (x - this.blx) - (this.tlx - this.blx) * (y - this.bly))) >= 0)
    							return true;
    							return false;
    this code does the same. takes the first 3 points (tl, tr, br) and 2nd  3 points (tl,br,bl) and checks if in those triangles the point is in. and really this works way faster and in my testing examples gives the same results. here's a link to "performance difference" which is almost double. 
    so where's the problem, i've put this function instead of the original and what happened is that in my game that i was testing it with happend this - the bombs sometimes fly through the objects and sometimes explode on the objects (they should explode every time they hit the object). now there is probably something different which i can't get through what and i was wondering if 

    Ashley you could take a look into it. you could gain some performance in collisions if this is optimized and people would be gratefull. it's not much but it will help. funny thing is that when i go from right side to left side bombs hit well, but form the left side to right side they "miss". like something is wrongly / badly calculated. do variables change in realtime in quads? that might be possibly a problem. [/p] [/p] p.s. - here are articles i've been using to "improve" solution[/p] [url=http://jsfiddle.net/z7x0udf7/3/]http://jsfiddle.net/z7x0udf7/3/[/url][/p] [url=http://stackoverflow.com/questions/2049582/how-to-determine-a-point-in-a-2d-triangle]http://stackoverflow.com/questions/2049 ... d-triangle[/url] (last answer is JS) [/p] [/p] i'm off to optimize some more and some other things.. i'll be back <img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile">[/p] [/p] p.p.s. pls check 4 posts behind Ashley about those assert statements that leave junk in code.

  • http://imgur.com/GPFfzbe

    :O wow just wow... 110% more efficient ... cant wait to see this at work <img src="{SMILIES_PATH}/icon_e_biggrin.gif" alt=":D" title="Very Happy">

  • Honestly, I have doubts this is at all helpful. I'm sorry, it's a very complex engine and it has years of subtleties coded in for long-ago bug fixes, backwards-compatibility purposes, and optimising for general-purpose performance rather than specific cases.

    For the leftover semicolons: this basically doesn't matter, but the reason it's there is because the exporter deletes all assert checks on export. It has to leave a semicolon so they still count as statements though. For example:

    if (x)
    If the runtime deletes the assert [i]and[/i] the semicolon, this effectively becomes:
    [code:1uagwfj6]if (x)
    What was previously an unconditional call is now conditional based on the if. So in this case your suggestion of removing the semicolons could create bugs where there were none before.
    "nextHighestPowerOfTwo" has never come up in any profiling measurements I've made so I believe any attempts to optimise it are just a waste of time.
    The collision checks are optimised for general-purpose performance. It's often possible to take some specific case and optimise that to be something like twice as fast, but it could make other cases half as fast. That's not a good tradeoff for an engine like Construct 2, since making some games slower and others faster is worse than having them all run at reasonable performance. (What if your game is one of the slowed-down ones? "It made other people's games faster" isn't much consolation.) For example the existing C2 segment intersection check can early-reject based on a bounding box check before it does any math. Your alternate version does some math calculations before it can reject, which isn't necessarily faster or slower over all, probably just different (a different set of cases will be faster/slower). The same is probably true of your contains_pt code.
    Then on top of that, there is a significant backwards-compatibility concern. One of the reasons I don't want to make any changes to these functions is they are absolutely core functions that almost every game heavily depends on. In the early days we made some tweak - smaller than your changes - and it broke a bunch of platform games because floating-point numbers started rounding in a different direction and ultimately it meant you couldn't fit in tunnels you could previously fit in to! At the time I reverted the change and it's been left like that ever since. So it seems very unlikely we could ship any such changes without breaking a wide range of games. I mean, you say yourself, your changes already broke your own game  It doesn't matter if it's 100x faster, if it doesn't work correctly we can't use it, it will break existing games, and if that is our overall philosophy, we end up building a buggy nightmare of a product which is fast but never works properly (quite a good description of how Construct Classic ended up).
    Finally, I'm afraid if you so much as change a single line of code in the C2 engine, we can't support you any more. For example we cannot accept any of your bug reports any more. If you have even a tiny change to the engine, and you report a bug, we will reject it in order to rule out the chance the bug is caused by your own engine changes (which is especially likely if it's an unfamiliar codebase). A warning to other users: this is also true if you are looking at these posts and decide to paste in any changes to the engine. If the code is not 100% exactly identical to what comes with the installer, we can no longer offer support.
    I don't see that you will be able to overcome any of these limitations in your approach, so I must discourage you from trying this. By all means hack away and experiment for your own learning purposes, but we will probably not use any of the changes, and we cannot offer any support if you have made a single change to the engine.
  • Ashley - thanks for the long answer

    i'll reply shortly (backwards) - i don't agree with you about overcoming limitations. limits can always be overcome, one way or another, that's why not a single software is "ever finished". always something to improve, upgrade, develop and so on.. when i'm using your engine to export my games i use it in it's native form as it came with installer, but i've got a separate installation for testing stuff out where i replace code and see if things improve/change etc.., however all the things i do i keep in my folder, each test i've done in its own file.

    on top of the support thing and including changes and tests that users comment / commit to forums, at least i would love if you'd take at least 5-10 mins to check them out and see if there is a possibility of improving something that someone has tested / tried and so on. whether you include that in the engine in some newer versions is ofcourse up to you, and your team alone. as a developer i have a need to tweak stuff, so if i can help that ends up great, and even if you do use any (even 1 out of 100 tweaks i do) it feels like a great job for me, to contribute to the devs of engine i use / follow /etc.

    and now to the tech part:

    • i've posted now 4 posts about tweaks / changes, and some of them do seem useless like the semicolons problem that is left after assert statements, but i've just mentioned it because i've noticed some random semicolons appearing out of nowhere. now i know that compiler probably ignores them, still uses a bit of time to process them, but ok. not much of a problem.
    • nextPowerofTwo - i didn't find it's use, but still a faster way is faster, at least by a bit, but also i think you're right when you say it doesn't appear anywhere in performance profiling.

    but the last 2 are pretty performance based...

    cr.segments_intersect - i've optimized that and it returns correct results, and have been testing with random values for both algorithms, both receiving random input data, but same data for both functions. it appeared that everytime results were the same and my function was faster. also your comment there is:

    "// Long-hand code since this is a performance hotspot and this type of

    // code minimises the number of conditional tests necessary."

    i would like if you could take a look at that one at least. I've noticed also that you mentioned that code is optimized for one type of game but not optimized for another type of game. i understand your approach to the problem when you say "general-purpose" and i didn't even try to go in some specific direction for it. Still a function that returns a value, should return always the same value, no matter how it's written, but that could impact it's performance. i highly doubt that one function can determine if a game is of one type or other.

    i agree that checks with math calculation can reject before/after, but after testing that function against the regular one, with over 10 000 000 input data, every time mine got the best of it.

    and what happens with the last (contains_pt) is a mystery to me, i might have missed something, but it's performance is double of the performance of default function. as much as i've understood you split the quad into 2 triangles and check if the point is in each. if it is in first you return true, and if not then you check for 2nd one, and return true if there, if not return false. that's exactly the same what mine code should do, and i my tests it did, but when used in engine it produces halfway good working. i'll try to fix that today and see if it gets better.

    i would be also gratefull if you could check the code and the 2 links i've posted and see if there is a possibility to improve that function.

    i also know how deep the rabbit hole goes when you have to be careful with floats and overflow and 4-5-6 decimal places and stuff..

    and also, i can give you my test html files (which include the JS with functions and how i've tested) if it will make it easier for you to see what happens.

    i'm pretty sure there's a lot more in the engine that can be fastened in microbenchmarks and improve overall performance of the engine, without depending on what type of game it is.

    p.s. sorry if my post is long, i'm not here to argue, insult or anything, i love C2, love your work, but i would appreciate if you'd "let" me at least post those improvements and take periodically a look, and even if you find 1 useful it will be my joy!

  • The only way we can actually verify we don't break or slow down people's games is to ship the change in a beta release, and my previous experience of this is much smaller changes had game-breaking results. Even just reordering the operations or putting brackets in a different place (e.g. (a * b) / c vs. a * (b / c)) can change the floating-point precision, increasing or decreasing rounding errors, and break some games which relied on the previous behavior. I already did a bunch of work optimising all this in the early days so it has pretty good all-round performance, and I just don't see the point of risking such enormous collateral damage for some pretty small changes.

  • Ashley

    so what you're telling me i should just give up and go make some games?

  • Ashley

    so what you're telling me i should just give up and go make some games?

    Not what I am seeing. Ashley said you can hack away all you want. But perhaps keep everything well documented to yourself for now, and come back if you have something more solid? Some of your numbers are intriguing, but with working in large projects myself sometimes that does not translate well once deployed. Depending on the server deployed too, the code can run worse then testing. Which in terms of C2, would be a nightmare if a bunch of apps started performing badly.

    Anyways, point I am trying to make is, if you enjoy what you are doing, continue on. I don't think you will get any immediate action, and you would need to do a lot of work on your end to prove this more. Something well documented and well tested. We are talking hundreds upon hundreds of hours of testing if you really want to try it. I think it would be hard to get Ashley to do that . . . you would be asking him to do those hours upon hours of testing and as the saying goes...if it ain't broke, don't fix it!

  • Ashley also said that he won't be checking this things out, that he used a lot of time to optimize things for general purpose usage. And i believe him. So why would i waste more time for this then he already did. Also if he believes that he can't optimize further (i think he can, but it's time consuming) then i'm fine with it. In the end it all comes to how your game performs on different platforms and in the end it's not about the engine, it's about the product that is made with that engine. For some tower defense games and such stuff that i am preparing to do, the engine itself is more then enough good. A lot of people complain about performance and such issues but they mostly come from compilers and wrappers (xdk / crosswalk / etc..) or users creating huge games that are overblown in size, etc, not following image usage and so on and so forth..

    i've built one game for PC as my own testing of engine and i've noticed that even with loads of objects and over 100 000 collision checks per second everything works fluidly.

    but particles are badly optimized, also for some reason, collisions appear to be higher then they should be, i mean collision system is pretty bad and every optimization is godlike for that - why? because when you have a screen like this:


    you don't expect 1095 collisions per tick, let alone 60 000 per second, and CPU usage of 30%.

    Ashley - can you elaborate this?

    for more info - ignore the object count - it's particles mostly and most of those objects have collision disabled.

    these objects have collision enabled:

    boats, player boat, islands and cannonballs, and that mine up there.

    so if you count all the "collidable" objects the count of them on this image is - 26.

    how do i get 1095 / 60 000 collision checks from 26 objects?

    forgot to mention this is on a gtx980M 8GB ddr and 4860HQ processor (3.6GHz) - and 30% usage ? wtf?

  • This is my main point:

    By all means hack away and experiment for your own learning purposes, but we will probably not use any of the changes, and we cannot offer any support if you have made a single change to the engine.

    So you can hack away if you like, but we can't exactly copy-paste snippets of code from the forum to our engine. (There's also copyright concerns and code licensing - I just thought of that )

    Off-screen collisions always count, and if you have a lot of different collision checking events, they all count too. So if you have 25 objects and you test collisions between all of them, that's already 600, suppose you have four repeated sets of events which makes it 2400, then at 60 FPS it's 144,000 checks per second. So you can easily fill large collision check numbers even with a small number of objects. The key is to reduce collision checks to only objects which need it, and eliminate redundant collision check events. (i.e. use sub-events to a single collision check event, rather than making the same check in different places)

    Again, nothing specific to Construct 2 there, it's just maths. But C2 does make it easy to accidentally make loads of checks, because things like checking every combination are implicit.

  • Ashley - i agree, but when i wrote code on forum i've pasted function as it appears in (for example) common_prelude.js, both original and changed, retaining variable names, return values and so on (but okay). p.s. didn't think about the copyright, since i'm doing it out of my own will so it's more of a helping hand (and not sure if i need copyright when taking something from stackoverflow or such pages).

    collisions thing - i'm destroying objects when they leave screen so they shouldn't count. the thing i didn't know is that it counts events? so when i have cannonball checking for each other object that can hit it multiplies? 1 cannonball = checks if hits boat/island/mine = 3 collision checks? and then 10 cannonballs = 30 collision checks? is this right?

    could family help with that? (example - 1 event for checking if cannonball hits family (of boat/island/mine) ) so it's 1 check and 10 cannonballs does 10 checks?

    this sounds pretty false to me, but is it working like this / could it?

    anyway here's an image, and i'd love if you could explain a bit in detail what is causing the increased collisions there:


    this is a part of code (ignore the comments) which does collisions with objects for cannonball. i've used 2 families (enemies (boats and other) and objects (islands mines and bouyes except crates) ) to check if canonball hits any of these objects, if it does.. it does it's thing (we're not discussing actions here so no need to look at them either)..

    so the problematic area then appears to be this "canonball is overlapping" and that is a collision check against 2 more objects? and instead of this it should be that bullet = 0 should be the first condition to check instead of collision because we want "watery explosion" when bomb stops and doesn't overlap anything (meaning it's on water). or should it be subevented when bullet = 0 ?

    thanks <img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile">

  • Ashley - also, what else is performance unfriendly in engine?

  • Ashley anything? can you at least look 2 posts behind and answer to that? thnx

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