How do I eliminate jerkiness/tearing when fullscreen

0 favourites
From the Asset Store
Eliminate all enemies in a fun game (style Angry Birds).
  • Define frame.

    A frame happens every tick.

    Unless you think it's something else?

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • Did you update your capx? I thought about the round(lerp( thing newt mentioned and when I went to try it's already there. It actually fixed the tearing for the most part here.

    I recorded it:. https://a.pomf.cat/owzfff.webm

  • andreyin newt the tearing did indeed go away! Victory!

    Defining frame now: Frame as in, animation. As in, if you record the screen, as in andreyin's capture for example, each *frame* is not a construct 2 tick, it's a construct 2 frame. Like fps. I don't know how else to explain it.

    And right now, even though tearing is fixed, jerky movement is NOT fixed. Have a look:

    What i want is that every frame, the screen scrolls by 1px. What's happening instead is (due to the rounding probably? or something else?) the background moves a different number of pixels each time. 1, 2, 3, even none.

    This is very noticeable in fullscreen.

    Is there a way to fix it? Is it just a matter of finding the correct player.Platform.MaxSpeed ? Is it something else? Ashley?

  • The only other thing I can think of is that it might be because it's scaled.

    Also there are some differences between fullscreen and the no window fullscreen.

    Anyway the frame you are talking about is when it's drawn.

    I believe the tick is basically between frames.

  • OK, when it's drawn. So how can I make the game draw 1 pixel movement per frame? Instead of irregular increments of pixels?

  • You would probably have to make your own movement system rather than use the platform behavior.

  • Hmm...

    One thing you could try is to use the "set minimum framerate" action to set it to 60. That way dt will stay at 1/60 instead of going to 1/30 at times. That should mostly solve the pixel step varying, but the game will slow on less powerful pcs. Dt will still vary a tiny bit so you may have the occasional instance where things will move 2 pixels instead of one. I suppose this can be tightened up a bit by doing like newt said and making your own movement system but that is really a last resort.

    Another idea to get things smoother is to only use speeds that are evenly divide into 60. 36 doesn't but speeds like:

    1,2,3,4,5,6,10,12,15,20,30,60 will give a more even motion.

    3

  • Thank you newt, thank you R0J0hound

    You would probably have to make your own movement system rather than use the platform behavior.

    You're right. doesn't that defeat the purpose of a game making tool though? Last time I made my own movement system, Ashley discouraged it, and for good reason. It couldn't handle slopes either. But even so, what kind of a custom movement were you thinking? Set X to self.X+60*dt ? Isn't that what platform movement does, when I've maxed acceleration and deceleration?

    Hmm...

    One thing you could try is to use the "set minimum framerate" action to set it to 60. That way dt will stay at 1/60 instead of going to 1/30 at times.

    Another idea to get things smoother is to only use speeds that are evenly divide into 60. 36 doesn't but speeds like:

    1,2,3,4,5,6,10,12,15,20,30,60 will give a more even motion.

    3

    I set the minimum framerate to 60 (even though I don't like the implication that it might run worse on some systems). And I set the player maxspeed to 30.

    Still some jerking. And parallax is even worse: by setting the background parallax layer to 50,50 , it would theoretically move at 15pixels/sec which is a number that evenly divides into 60.

    But in practice, it creates a ton of jerkiness!

    When I set player.maxspeed = 60, I do get a smooth result.

  • "doesn't that defeat the purpose of a game making tool though?"

    No, not really. The purpose of the engine is to make things easier.

    The big problem with doing your own movement isn't moving on the x axis, its getting the y right.

    With that in mind maybe you could try something like disabling the regular controls, and setting up your own.

    Something like key d is down, player set x vector to +1.

  • It's much easier to investigate with confidence with a minimal .capx. I haven't sifted through the whole project, so this is only speculation from a glance, but I think it's because events 4 and 6 apply their own rounding to the scroll position. You really should not do this - turning on pixel rounding also rounds the scroll position. The best approach for this is to pretend scrolling is perfectly smooth, but let pixel rounding mode handle rounding the scroll position. In particular event 6 is using a different rounding (floor vs. round in another event), so these rounding modes could be doing different things creating a choppy motion. Removing these unnecessary rounds seemed to help.

    Also it looks like the speed you've chosen is 36 pixels per second. This will alias with the common screen refresh rate of 60 Hz. 36 pixels per second divided by 60 Hz = 0.6. Since you've enabled pixel rounding, point sampling etc. you can only scroll in whole pixels (by default you get smooth scrolling with sub-pixel positioning, but this is commonly turned off for retro games). However you have chosen a value that causes the object to move 0.6 pixels per frame. So then you will get an irregular pattern of scrolling one or zero pixels depending on the rounded total. It will look like this:

    Frame 0: position = 0, displayed at = 0

    Frame 1: position = 0.6, displayed at = 1 (+1)

    Frame 2: position = 1.2, displayed at = 1 (+0)

    Frame 3: position = 1.8, displayed at = 2 (+1)

    Frame 4: position = 2.4, displayed at = 2 (+0)

    Frame 5: position = 3.0, displayed at = 3 (+1)

    Frame 6: position = 3.6, displayed at = 4 (+1)

    Frame 7: position = 4.2, displayed at = 4 (+0)

    Note it had an on-off pattern until frames 5 and 6 which both advance 1 pixel - the 0.6 increment makes it irregular. This means that although I believe everything is working correctly in the engine, it still looks jerky - scrolling doesn't look good with irregular updates, the human eye much prefers regular updates. This is also why a speed of 60 looks better: it increments by a regular 1 every frame. dt variations will slightly randomise this too, but usually it's not so bad, with good v-sync it should fall within the rounding error. You can turn it off if you really want to by forcing a minimum framerate, but then you get the other shortcomings of a fixed step (weak devices run in slo-mo, 120Hz gaming displays run at double-speed instead of smoother, jank makes the game pause instead of moving past it, etc).

    Often people blame Construct 2 if something doesn't look good, but I think in this case no engine or technology is going to save you from these game design choices. Incrementing by 0.6 pixels a frame and displayed rounded to the nearest is always going to be irregular, due to maths, not code. For this kind of thing you either have to pick all your values super carefully so they divide in - but note they will break on displays with a different refresh rate! or if you use fixed dt, the game runs at a different speed on displays with a different refresh rate! - or just let it scroll smoothly...

  • Ashley newt thanks for the replies <3

    Ashley you're absolutely right, I was wrong to not have accounted for precise pixel per frame speeds. And thank you for the thorough reply.

    Platform.maxSpeed= 60 pixels per second is the ideal speed, as we've all figured out.

    The background layer, at 50,50 parallax also scrolls smoothly, presumably moving at 30pixels per second or 1 pixel every 2 frames. (EDIT: I screen captured it and both player and background layer are jaggy, but not very noticeable)

    _________

    Can we account for the fact, though, that Platform.maxSpeed = 30 has the jaggiest scrolling on the parallax layer?

    The player would theoretically move at 1 pixel every two frames (30 p/s divided by 60Hz = 0.5), which sounds fine. Regular intervals are fine for the human eye as you said, and I can confirm as an animator.

    In practice, however, player moves at 1 pixel every frame, except for rare frames when it moves 0 pixels. I don't know why.

    The parallax layer would theoretically scroll at 15frames per second, which would produce a regular pacing of 1pixel every 4 frames, which would also be fine. However practically, it staggers even more: 1px,0, 1px, 0, 0,1px, 0,0, 1px, 1px, etc

    I think this is what has confused me most. I can't account for that error in rounding.

    You can try it in this stripped down minimal .capx (scrollx = player.X for simplicity, I do not introduce my own rounding anywhere)

    https://dl.dropboxusercontent.com/u/28087823/Construct%20Examples/DAIKO_TWINS_JERKING_MOVEMENT/jerking30.capx

    (I tested by screen capturing a gif of the game window)

    Is there a way for the engine to evenly distribute those increments in time? Has anyone else ever checked that 60px/sec movement, with pixel rounding on, does indeed move the player 1 px per frame? Because my tests say it isn't so.

  • Hmm... I think the problem with using 0.5 is it's exactly in the middle of the rounding direction, which makes it round semi-randomly due to floating point imprecision and dt variation.

    Floating point math isn't exact in processors, due to the binary representation, e.g. 0.1 + 0.2 = 0.30000000000000004. This happens literally at the CPU level, so again no technology or framework is going to save you, it's just a fact of floating point math on CPUs that regularly trips people up. Add to that the fact dt is not always an exact value, since it's based on timer measurements, and in practice your frame advances are going to look something like this:

    Frame 0: position = 0, displayed at = 0

    Frame 1: position = 0.50000000000000001, displayed at = 1 (+1) - rounded up

    Frame 2: position = 1.0000000000000001, displayed at = 1 (+0)

    Frame 3: position = 1.4999999999999999, displayed at = 1 (+0) - rounded down

    Frame 4: position = 1.9999999999999999, displayed at = 2 +(+1)

    so the slight variations in the math cause random rounding directions and create an irregular progression rate again.

    You can lock dt so it doesn't vary, but note setting a minimum framerate of 60 doesn't do that reliably - if dt was measured as 16.6ms (~60.24 FPS) instead of exactly 1/60, then it introduces a variation of 0.066666... ms. To avoid this kind of variation around the framerate you will need to set a much higher minimum framerate, e.g. 100, which would reliably lock dt to 0.1. In fact to cover all displays you should probably choose 200, and then base everything off a regular dt value of 0.05.

    Even so, what's to say the game won't offset something a tiny fraction at some point and then get all the irregular updates again? Then when you throw in to the mix a 50% parallax layer, you're probably opening another can of worms. This is much harder than I think most people really realise.

    My preferred solution would be to just use "high quality" fullscreen mode and turn off pixel rounding. Then you still get the blocky look, but things can move smoothly. This basically solves all the problems you will face, since larger windows mean even smoother scrolling, rather than making scrolling artefacts even more obvious. However it does look less like a lo-res display. If you really want that look I think your best bet would be to do something like the original retro games would have done and force it to move only on alternate ticks. You can do this fairly easy by enabling and disabling the platform behavior based on if it's an odd or even tick, and use a double speed of 60 instead of 30 in the platform behavior. This looks OK if you turn off the minimum framerate (since it reliably moves 1px on alternate frames), but then the parallax background hurts my eyes when blown up to a 2K screen, because it's not updating very often and creates a pretty bad flickering effect due to the parallax slowing down the scroll rate.

    Maybe a good compromise would be allow the player and scroll position to be smooth, but round the positions of the rest of the objects in the game.

  • Ashley thanks again for the in-depth reply. I'm not implying in the least that any of this is simple and uncomplicated, and I know you're a genius programmer, and I'm super thankful for C2, and the community and your guidance.

    I think I understand now the limitations of half pixels.

    I agree with you, high quality and pixel rounding off *does* solve the smooth scrolling problem. But it introduces subpixel movement.

    But you say this can be prevented too, by enabling and disabling the movement? Would you mind helping me out a bit? Your solution is

    * high quality full screen scaling

    * pixel rounding = off

    * tickcount%2 = 0 (even ticks) -> Platform enabled,

    else: plaform disabled

    Is that right? I can't get it to do what we're after. Am I doing something wrong?

    Let me define the new problem that high quality + pixel rounding off creates for me:

    It does preserve the blocky sprite style. But it allows sub-pixel movement, which destroys pixelart completely, as do rotated non-square pixels.

    Retro platformers, and neo-retro platformers like Shovel Knight (coded in a custom C engine) don't allow sub-pixel movement.

    As is evident from studying this Shovel Knight gif, no sub-pixel positions occur at all, even when scrolling

    You probably had an amiga or speccy growing up. Their respective emulators can handle unwavering fps and pre-FPU pixel-perfect position calculations admirably.

    I promise I'm not asking you to code my game for me, I'm just completely baffled. If you're saying C2 isn't to blame, then it's capable of doing what I want, and I just can't see a way to do it. That's why I'm asking for help, we'll make a perfect capx and save it as a template and bury this stupid issue forever.

    Would it help if I kept a decimal value position stored in a variable and only move the player when its integer is >0? Then subtract the integer and keep the float, which will continue to increment in irregular ways (because of dt). That way there's no brute force rounding, and even 0.5 increments will only affect movement in a predetermined way.

    Is that a good direction to go? I'm probably not clever enough for all this. But if you tell me it's possible, I'm determined to get proper pixel-quantized movement without crippling rounding and smooth scrolling with no sub-pixel movement.

    thanks again for your time, I know I'm a super small niche of C2 clients

  • Hi christina,

    I was looking at your capx again and did one slight tweak.

    I ignored the speed having to be able to evenly divide into 60, and using the minimum framerate action.

    Instead I tried doing rounding myself. So, instead of the pin behavior I set TWIN's position to (int(player.x), int(player.y)), and the scrollx to int(player.x) every tick.

    https://dl.dropboxusercontent.com/u/542 ... utter.capx

    Before the player itself was the most jerky and made everything else look worse. However after the change it looked acceptable to me. Any stuttering I got was basically the same as I always get on my machine, which isn't so much to do with js as it has to do with the browser's renderer I think (well, partially confirmed by a previous test I did that used the v8 js engine with sfml).

  • R0J0hound thank you for all the help again... Unfortunately it doesn't look acceptable to me. Compare it to the perfectly smooth scrolling of Shovel Knight above. I'm despairing

    For example, in your capx: with 60px/sec max player speed scrolling should be 1 px per frame (1,1,1,1,1,1, etc).

    Instead it's 2,1,1,2,1,2,2,2,2, etc I don't know what's going on.

    Ashley I still haven't managed to implement your solution. Is the engine capable of smooth and accurate scrolling? I really can't get it to behave

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