simulatedTea's Forum Posts

  • 14 posts
  • Okay, after playing around with collisions for a week or two I think I'm going to let that feature go for the time beeing.

    That one demands more time and dedication and definitely does not belong into this behavior.

    Soo, I think I'm going to wrap it up with this one.

    Now i wonder what should the procedure be?

    Should I post a new entry to the 'Finished Plugin' subforum or is one friendly mod simply going to migrate this thread?

    Kyatric

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • Hi $crowd,

    30 yo white male here.

    Finally, after my first 3 years in an IT job -- (first 3 years in a proper full time job, really) -- I can put the skills acquired to good use in pusuite of the default dream of my generation: putting together _the_ game.

    Let's see how far I can make it.

    Looking forward to meeting you.

    (at least the ones i can agree with )

  • Savvy001

    Hmm. I don't know much about CPU intensity in each case.

    Also I am not sure what kind of 'moving in correspondance to gravity' you mean.

    I could think of a -- maybe a little complicated -- way to orient a sprite downwards using a dedicated weight. (again - i have no intuition of how wasteful that might be in terms of CPU/GPU)

    So ... did you mean something like this?

  • Savvy001 maybe the Physics behavior can already do that - i am not sure. (after today)

    Could be worth a look, if you are serious and have the time.

    (I'm sorry if this is not the answer you were hoping for.)

  • Beware, long story.

    I tried combining my movement with the build-in physics behavior. Because, you know, would be nice if I wouldn't have to do my own gravity (although 'Physics' doesn't have a config value for the gravitation, like I do), friction and elasticity and stuff, if I can just use whats already there.

    That didn't go too well.

    Basically my object just gets stuck. (Which feels somewhat familiar. Either Physics just refuses to move if it detects a foreigner or it constantly resets speed or something. I've been there.)

    So I took a peek at the code, and sure enough, it reads like one of my earlier drafts.

    "Remember position and compare."

    "If external movement is detected, measure and set own speed to the one observed."

    and

    "Reset own speed once external source stops interfering."

    Just without the nice combinability feature that I settled for lately.

    So I put on my megalomania hat and thought, maybe if i rearrange things a bit, make'em work my way, I can make the physics Plugin compatible and cut the amount of work my behavior has to do.

    So, I roll out my pattern of 'collaborative movement' and yay, it moves.

    Only that it seems to be 'falling' towards 2 o'clock. Wait, what?

    Is that a bug? Did I confuse x and y by accident? But then where does that angle come from?

    ...

    angle...

    I rotate the object and yupp, sure enough, it 'falls' straight up in the sky. hrmpf.

    Its not a bug - its a feature. The gravity is local to the object.

    Maybe i should not have ticked the 'Prevent rotation' config, so it could rotate to find 6 o'clock and fall down.

    But no - it just starts rotating, which makes it fly circles around its anchor. hrrg.

    Looking closer at the Physics I notice, -- 1 -- you can configure gravity via an action. It is labled 'Set world gravity'. (On a gravity local to an object? what might that do?)

    And -- 2-- that it can do something called 'joints'. It accepts options that read a lot like mine. This thing can probably obsolete my behavior.

    Why did nobody tell me?

    However, within 5 minutes of trying I could not make it do what my behavior does. I could have just googled for the docu or a tutorial at this point, but instead decided to blow off some steam in a wall of text.

    Now, I'm kind of at a loss here. What should I do? Abandon my behavior? Or finish it anyway, just in spite.

    Well a few things are to be said here.

    That Physics behavior is part of the C2 core. It has a far more complete set of features than I need atm. It is probably much more optimized than my humble pile of code. (It lies with a file bearing the awe-demanding, magic letters asm *subconscious quiver*.)

    But! there are problems.

    Actually the paragraph above is the problem. This behavior does too much. Its complex. (At least, I don't get how most things there work.) It does it all - maybe because that allows for better optimization? And it cannot be used only partially. It is a God-Behavior. That is not the thing I expect in a modular toolbox. At least not the first thing.

    I have already been thinking about this with my behavior. At the time of this writing, it does 3 things. A rubber band. Gravity. Drag. These could also be 3 separate behaviors. If they could play nicely together.

    So it comes down to the question how small, how specialized should modules be?

    Thats actually a pretty old question, you may have heard it in the incarnation of 'many small specialized linux-tools vs. a Windows-Monolith kernel' or systemV vs. systemd or...

    I think the pros and cons are pretty straight forward.

    Many small, focused behaviors:

    easier to explain & understand

    can only use the ones really needed

    more work to click together the desired behavior from its aspects (though this might be outweight by the more demanding work to understand the one-does-it-all behavior)

    possibly a lot of overhead for duplicated internal state and calculations

    -> Easier & low initial hurdle, suboptimal for professional, high performance or other advanced use cases.

    Multi-functional complex optimized behaviors:

    more difficult to understand / learn

    may enable andvanced behaviors which require an in-depth connection between simple components

    may not be flexible enough to be reduced to only the required functionality

    less overhead from duplication

    -> high effort to learn/master, interessting/required for advanced & cool projects.

    Now from the perspective of the C2 project I can understand that we don't want to prevent the cool&advanced stuff to be possible.

    But on the other hand the ease of use, especially for a non-programming audience is also a big part of the target group of C2. (Which, i may have to throw in here, it does a pretty good job at, at least from my POV, and atm i'm really excited by this. Awesome job guys. Really.)

    So, ultimately, I think we need both.

    Have a 'Simple Movements' section, containing tiny, stupid, specialized stuff like 'gravity', 'friction' and 'solid'.

    And an 'Advanced Movements' section for the likes of 'Physics', maybe as 'Combined Physics'.

    I, for my part, would like to see Physics additionally available in smaller aspects. Though I'm most likely not able to do it by my self. And some cross-cutting concernes like collision-detection might not work like this at all. I guess I would have to start with finishing this plugin. Seems like a legit first step.

    I have to put a disclaimer here: I have not much of an idea, of what I am talking about. I never tuned a mobile app for acceptable performance, I don't know how precious the CPU cycles there really are and what are the tradeoffs to be made.

    I also don't know what the dev's already tried, what failed and what didn't. Providing a working yet accessible set of compatible modules is a very non-trivial problem.

    I guess, i just wanted to get that off my chest. For anyone, who made it this far -- I am sorry. Thank you for your time and maybe your sympathy. Thanks for reading.

    And in case this post is beating an already dead horse/debate, maybe someone could link the earlier iterations for me to find.

  • TL;DR

    Want to write a behavior that is supposed to play along with other existing movement behaviors? Is it sensitive to single-frame-disturbance? Copy the code below, see if it works for you. Might save you some headscratching.

    /TR;DR

    Ok, I was pondering a problem this weekend.

    Here it is.

    Context (the X of the XY Problem)

    I want to build a behavior that moves an object.

    It does so, by having the objects speed as internal state. (Im thinking of it as 'momentum'.)

    And I want to be able to have multiple instances of it on the same object.

    So basically my behavior should be able to tolerate other people moving its object as well.

    (This should be good modular design, right?)

    So, my behavior needs to track the movement other behaviors do and factor it in.

    (The reason beeing, that i want to preserve momentum, to provide a nice smooth movement feel.)

    Plan

    Remember the last location this behavior set the obejct to and compare it with the location it finds itself in at the next invocation to measure speed.

    Done so far

    So to attribute for other collaborators moving my object, what i do every tick is roughly:

    • Compare difference 'delta' of instance position now and 'lastPosition'
    • Compute 'externalSpeed' applied by collaborators: 'delta' / dt
    • Set my internal speed to the average of internal speed and 'externalSpeed'
    • Do the actual behavior specifc stuff to set a new speed + position
    • Remember that new position as 'lastPosition'

    This works pretty well most of the time.

    Problem

    Now you might or might not have already spotted it, but this only works as long as the frame rate is stable.

    Here is why.

    In the most simplified scenario I have 4 steps:

    • Drawing of the new frame begins. Time since the last frame is measured: dt
    • Behavior A is triggered. It moves the object according to its internal 'speed' and dt
    • Behavior B is triggered. It detects the movement of A, correctly estimates A's speed and accounts for it. B also moves the object.
    • Other stuff is happening and more time is passing. Say dt_2.

    Now, thats all fine and working. The problem starts when this is repeated the next frame:

    A is triggered. It gets handed dt_2. It also sees that its object has been moved.

    If it tries to estimate the internal speed of B and dt_2 is noticable different from dt it will get a wrong estimate.

    (B-speed -> movement by dt -> new object position -> converted back to speed via dt_2 -> wrong)

    So putting us in the perspective of a behavior on an object that tries to measure its objects 'speed' from other sources there is no easy way around this.

    The (hypothetical) interval over which dt is measured is different from the one we can measure the location 'delta' and we cannot know by how far we are off.

    Why is this relevant?

    First off: dt is just the inverse of the fps. And the fps are far from stable to begin with.

    Someone might be resizing his browser or beeing notified by his phone about a call - we just cannot assume too much about it.

    Then, in my current build r195, there are a few artifacts which had a notable effect on my behavior.

    • The first 1-2 frames (at least when started from C2 directly) come back with a dt = 0. This is not so bad, but it put my object into NaN the first time.
    • When using the 'Debug' Mode to Pause/Resume the first 1-3 frames may come back with a dt of ~ 5ms. This is significantly less then the average 60 FPS 16ms. This can also happen when switching between my browser tabs and back to the C2 app.
    • When switching windows away from the browser and back to it (like with detached browser-developper tools) the engine sometimes comes back with exactly 100ms for dt. Looks a bit like a timeout state for a frame, but yeah. Again far off from the usual 16ms 'good' case.

    What to do?

    That - of course - depends heavily on the behavior you want to write.

    I tried a few things, skipping frames, averaging dts. But since i'm after smooth movement I figured it best to use a 5 sample median to ignore the 1-2 frame offs in 2. and 3. as much as possible. Which comes at the minor cost of sorting a 5 element list each tick.

    Concretely, here is what I do:

    • OnCreate() this.dx = 0; this.dy = 0; this.lastX = this.inst.x; this.lastY = this.inst.y; this.medianDt = 0.016; // assume 60 FPS this.lastDts = [0.016, 0.016, 0.016, 0.16, 0.16]; [/code:15c75kcw]
    • tick() this.getLast5MedianDt(); this.pickupExternalImpulse(); if (this.enabled) { this.actualBehaviorStuff(); } this.lastX = this.inst.x; this.lastY = this.inst.y; [/code:15c75kcw] with behinstProto.getLast5MedianDt = function () { var dt = this.runtime.getDt(this.inst); this.lastDts.pop(); this.lastDts.unshift(dt); var sample = this.lastDts.slice().sort(function(a,b) {return a-b}); this.medianDt = sample[2]; } behinstProto.pickupExternalImpulse = function () { if (this.lastX !== this.inst.x || this.lastY !== this.inst.y) { var deltaX = this.inst.x - this.lastX, deltaY = this.inst.y - this.lastY; this.dx = (this.dx + deltaX/this.medianDt)/2; // merge own momentum with external one in equal shares this.dy = (this.dy + deltaY/this.medianDt)/2; } } [/code:15c75kcw]
    • plus all the other stuff, like saving all 6 variables to JSON and handing out 'Debug' Mode infos...

    (above code may be considered CC0 licensed)

    Any comments on how to better/properly do it are welcome.

  • It may be a good thing if there is still some time left.

    I still want to flesh it out a little more. Add actions to change the band length at runtime, collision detection, etc...

  • Hey Somebody,

    I tried quite a few things. This is the first solution that somewhat works to build chains with. (And does not totally blow up the complexity of the code or the usage interface of the behavior itself.)

    It is still kind of twitchy though, and I probably would not recommend productive usage of complex structures build in this way. Although you might find something that works for you playing with the config parameters.

    Maybe still a bug in there. May also be as good as it gets for now. We'll see.

  • The behavior is completely determined by the configured values.

    'Size' or 'Mass' would effectively just add to - or rather substract from - the 'Stiffness' value, if you try to compensate for size.

  • Haha, I didn't even get that far with my testing yet.

    What exactly are you thinking of? / trying to model?

    I am still thinking about supporting multiple 'targets' to be tied to.

    Having a sequence of items and each tied to _both_ its neighbors could provide what you are looking for, if i read you correctly?

    (edit: could also look totally weired, if i think about it... )

  • [RESERVED}
  • [attachment=2:1glg6y09][/attachment:1glg6y09]Good localTimeOfDay everyone,

    I just started playing aroung with writing C2 Extentions a bit.

    Started with a go for a 'rubber band' behavior. ie. one object tied to another with a bit of dynamic.

    I couldn't find any other Plugin doing it, but might have missed something.

    Take a look, if you like. .

    There is also the code. .

    And in the rare incident of one of the more experienced C2 Veterans taking a look at the code, pointing out obvious mistakes, highlighting C2 best practices or just making useful suggestions is highly welcome.

    EDIT:

    Updated the plugin (v0.7) to allow the usage of multiple bands on one object.

    (Docu says, this may break any existing usages of the plugin, if any should exist yet.)

    Relevant demo:

  • Hmm. Apparently the recent stable release 195 fixed this issue for me.

    Nice. Good work guys, even w/o a bugreport. )

  • Hi there, everyone.

    I am just jumping in to try and compose a nice movement behavior.

    While struggling with the obligatory minification-pitfall (don't internally use string-literal object keys) I am running into the charming, attached error message.

    While I am positive to have a working java setup (minification worked a few minutes earlier) I was wondering if there is a way to get more specifics about the nature of the actual error.

    A Construct 2 log file of some sort, perhaps?

    I would be grateful for relevant hints and tipps.

  • 14 posts