0
\$\begingroup\$

I have a simple game that is using a Unity animation to move an object around the screen in a 2D game. Think space ship following a path like Galaga. I made a GameObject, animated it moving around the screen, saved that as a prefab. I instantiate that prefab, child my object to it, and play the animation.

So far so good. The animation is smooth as silk.

So next I add players (space ships) and they shoot projectiles at the enemy.

Here's the issue. As soon as the players start shooting I can see the motion of the enemy is no longer smooth. It's janky.

Now, my first thought would be that the problem is the players shooting are calling Instantiate and Instantiate is slow so I'm not hitting 60fps. Okay fine, I implemented object pools and use GameObject.SetActive to turn them on and off. I run the game, same problem. Motion of enemy is smooth when no shots are fired. Motion is janky while shots are being fired.

Someone tells me GameObject.SetActive is slow.

Okay, let's check. I add an FPS graph. The FPS is pretty smooth according to the graph. It seems like I'm at 60fps 100% of the time shooting or not.

So ... what gives? If I'm always hitting 60fps then why does shooting cause the motion of some other unrelated object to become janky and more importantly how do I fix it so it's not janky?

Unfortunately it's hard to show the issue. I tried recording the screen using quicktime with and without shots. The screen recording is 60fps and it shows no jank with or without shots even though I could clearly see the jank while recording when the ships are shooting.

I recorded with my iPhone at 60fps. You should be able to see that this video is mostly smooth. There are 3 or 4 janks early on (which weren't there in reality, it's a sync issue between the phone and the TV), but basically the motion of the thing swinging left and right is smooth

Where as this video with the ships shooting it should be very clear is full of jank. The motion of the object swinging back and forth is not smooth at all and yet if you look at the FPS meter in the top left corner you can see processing time (blue) is almost nothing. It would fill the graph all the way to the green if it was taking 1/60 of a second to compute a frame. The green is the framerate and it's a pretty consistent 60fps.

That kind of makes it seem like a unity bug related to swapping frames or something else happening late.

Note I'm using a Mac Mini but the game is seriously simple. There's about 20 small/medium sprites on the screen and nothing else.

I posted a repo here although I suspect you won't be able to repo the issue unless you also have the same or similar model Mac Mini since I can't repo on my Macbook Pro.

Update

So some more data. I tried turning off vsync (QualitySettings.vSyncCount = 0). The game runs 310 to 350fps at all times clearly showing the issue is not speed. It should be able to hit 60fps with no problems. Of course with vblank off there is notable rippling (it's tearing but given the content of the game I don't see what I normally consider tears. Still I might end up using this mode or at least making it an option as it looks much better than the jank I'm seeing with QualitySettings.vSyncCount = 1.) If I set the target FPS to 100 then I see serious tearing. I tried a target FPS of 60 and it looks the same as with vSyncCount set to 1 (in other words, janky). Tried a target of 65 and it looks different but still bad. sigh....

update 2

Can repo on my MacBook Pro by connecting it via HDMI to my TV. If I display the game on my TV I get the jank when shooting. I even tried turning off the Macbook Pro main display by connecting an external keyboard and mouse and then closing the lid just to make sure it wasn't an issue with two displays Same issue.

update 3

So when repoing with my Macbook Pro MacOS would only give me options for scaled resolutions on the TV (I'm using a 4k TV). My game is a pixel art game so I only needed the TV to be in 720p mode at most. MacOS only provides "720p (scaled)" which I'm guessing means the display is running at 1080p or 4k, the OS is drawing 720 but scaling the result.

So I went looking for a way to force the Mac to go 720p and found this Q&A. I downloaded the software from the accepted answer, SwitchResX. I tried forcing the Mac to emit a 720p 60hz signal. That did not fix the problem. Then I tried 720p 50hz and the jank disappeared! Also tried on Mac Mini and it solved the issue there too.

As pointed out above this does not seem to be a perf issue. The game runs plenty fast. It's some kind of timing issue with Unity and how it's swapping the screen buffers on Mac such that sometimes it misses its chance to swap them and an old frame gets displayed (or at least that's my guess since screen capture shows every frame).

In any case my use case is for a promotional event so I can purchase SwitchResX, install it on the machine in question and use that for the promotional event.

Still, if it was an end user game it would be nice to know how to fix it from unity's side

\$\endgroup\$
  • \$\begingroup\$ This sounds like it might not be a slowdown, but judder. Judder happens when you display an object in a position that's a little ahead or a little behind where it should be for the moment it's being displayed. Even if its average rate of motion is right, these little mismatches can make it look choppy or like it's vibrating. Usually it's a matter of not correctly interpolating between fixedupdates, or not correctly adjusting a displacement with deltaTime. It's particularly prone to popping up in camera motion, if the camera moves to follow something that moves at another time in the frame. \$\endgroup\$ – DMGregory Apr 8 '18 at 15:51
  • \$\begingroup\$ Can you show us a minimal sample of code that will let us reproduce the issue? \$\endgroup\$ – DMGregory Apr 8 '18 at 15:54
  • \$\begingroup\$ The thing is, given the capture is perfect that seems to suggest the issue has to do with double buffering and not showing the correct buffer (telling the OS a little to late to display the other buffer). In other words, since the capture has every frame with no jank that means the game produced every frame correctly, all the happened is that some frames didn't get displayed on the monitor. Also I'm not sure I can repo. For example the issue doesn't happen on my Macbook Pro. It only happens on the Mac Mini. That might suggest a perf issue but as I mentioned the perf is fine. \$\endgroup\$ – gman Apr 9 '18 at 2:03
  • \$\begingroup\$ Added some more info. Also posted a github repo. Figured out that I can repo it on my Macbook Pro by connecting it to a TV via HDMI \$\endgroup\$ – gman Apr 11 '18 at 4:43
  • \$\begingroup\$ The issue going away when displaying at 50 Hz is suggestive. By default, Unity runs its physics update at 50 Hz, so if you haven't enabled interpolation, you can see judder between objects moving with physics and objects without. I'm on my phone so I can't easily dig through your code — are you moving physics objects anywhere that might be connected to this issue? \$\endgroup\$ – DMGregory Apr 11 '18 at 9:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.