Stuttering graphics

Hi

I have been speaking to @peach who suggested this issue might have been raised but can’t find it in the recent forums.

I have used her code just to test an issue I am having and it reacts the same. Basically I have a scrolling infinite background but stutters only via slightly but means I am unable to achieve a smooth running animation or experience.

I am using custom daily build 2011.715 as it sorted my bloating of OF / gamenetwork files out and have been reluctant to get another build. Do we know if this is an issue that has been fixed since then?

For your info the code used is from @peach’d tutorial but also is based on the jungle scene demo

[lua]local paper = display.newImage(“background.png”)
paper:setReferencePoint(display.CenterLeftReferencePoint)
paper.x = 0
paper.y = 0

local paper2 = display.newImage(“background.png”)
paper2:setReferencePoint(display.CenterLeftReferencePoint)
paper2.x = 0
paper2.y = 480

local tPrevious = system.getTimer()
local function move(event)
local tDelta = event.time - tPrevious
tPrevious = event.time

local yOffset = ( 0.15 * tDelta )

paper.y = paper.y - yOffset
paper2.y = paper2.y - yOffset

if (paper.y + paper.contentHeight-240) < 0 then
paper:translate( 0, 480 * 2)
end
if (paper2.y + paper2.contentHeight-240) < 0 then
paper2:translate(0, 480 * 2)
end
end
Runtime:addEventListener( “enterFrame”, move )[/lua]

Obviously my game is far more complex than this but wanted to take it back to basics to ensure I wasn’t just overloading my game with too much complexity and affecting the fps. This proves to me that thee is an issue but not sure where it lies. [import]uid: 103970 topic_id: 21203 reply_id: 321203[/import]

Check out the graphics optimization tips on this thread if you haven’t already. http://developer.anscamobile.com/forum/2011/12/03/tips-optimization-101

I wish it was more prominent cause there’s a lot of good info in there. [import]uid: 27183 topic_id: 21203 reply_id: 84006[/import]

Thanks Don, an incredibly helpful link and agree this should be lesson number 1 before trying any code.

What I have done is taken a couple of examples and tried optimising them. I have ignored the jungle scene demo previously recommended as it uses LevelHelper for parallax scrolling while that doesn’t appear stuttering it surely is possible in raw code.

So I created a simple parallax scroller optimising the star / snow code found here: http://developer.anscamobile.com/code/simple-parallax-starfield-or-use-it-snow and used the techniques in the link you provided.

I have also included a frames per second monitor to see the effects I got from optimisation(http://developer.anscamobile.com/code/output-fps-and-texture-memory-usage-your-app)

The code I wrote eventually is:

[lua]local circles = {}
local stars = {}

– initial vars
local stars_total = 300
local stars_field1= 100
local stars_field2= 200
local stars_field3= 400
local star_width = 1
local star_height = 1

lowerStarfield = 1.4
middleStarfield = 2
upperStarfield = 3
circleCount = 10

local fps = require(“fps”)
local performance = fps.PerformanceOutput.new();
performance.group.x, performance.group.y = 0.5 * display.contentWidth, 0;
performance.alpha = 0.6; – So it doesn’t get in the way of the rest of the scene

_H = display.contentHeight
_W = display.contentWidth

local manageCirclesNormal = function()
if(#circles < circleCount) then
local myRand = math.random
local circle = display.newImageRect(“circle.png”, 67, 64)
circle:translate(myRand(_W, _W*2), myRand(0, _H))
circle.name = “middle”
circle.index = #circles + 1

circles[circle.index] = circle

myRand = nil
circle = nil
end
end

local updateCirclePositions = function()
for i = #circles,1, -1 do
local circle = {}
circle = circles[i]
circle:translate(-middleStarfield,0)
if(circle.x <= -20) then
local myRand = math.random
circle.x = myRand(_W, _W+200)
circle.y = myRand(0, _H)
print(“x”, circle.x)
print(“y”, circle.y)
myRand = nil
end

circles[i] = circle
circle = nil

end
end

– create/draw objects
for i = 1, stars_total do
local star = {}
local myRand = math.random

star.object = display.newRect(myRand(_W),myRand(_H),star_width,star_height)
if (i <= stars_field1) then
star.object:setFillColor(100,100,100)
elseif (i <= stars_field2 and i > stars_field1) then
star.object:setFillColor(155,155,155)
elseif(i <= stars_field3 and i > stars_field2) then
star.object:setFillColor(255,255,255)
end
stars[i] = star

star = nil
myRand = nil
end

function updatestars(event)
for i = stars_total,1, -1 do
if (i <= stars_field1) then
updatePositioning(i, lowerStarfield)
elseif (i <= stars_field2 and i > stars_field1) then
updatePositioning(i, middleStarfield)
elseif(i <= stars_field3 and i > stars_field2) then
updatePositioning(i, upperStarfield)
end
end
end

function updatePositioning(position, speed)
stars[position].object:translate(-speed ,0)

if (stars[position].object.x < 0) then
stars[position].object:translate(_W ,0)
end
end

Runtime:addEventListener( “enterFrame” , manageCirclesNormal)
Runtime:addEventListener(“enterFrame”,updateCirclePositions)
– let updatestars run at enterFrame
Runtime:addEventListener(“enterFrame”,updatestars)
[/lua]

Now don’t get me wrong I am achieving FPS of around 50 -55fps which isn’t to be sniffed at. However, the stutter of the graphics is occasionally there.

Take a look and see for yourself. Any idea what is causing it? Is there something significant that needs optimising to make it smoother?

I was so close to launching my game but have become obsessed with optimisation and the quality of experience that I need to get this resolved.

Any help would be appreciated [import]uid: 103970 topic_id: 21203 reply_id: 84198[/import]

Hey AParachutingFrog,
I’m assuming in your config.lua you have fps set to 60…

and also I have seen a difference with certain code

that:

  
circle.translate(circle, myRand(\_W, W\*2), myRand(0, \_H));  
--the above seems to be faster in some cases...for some reason  
circle:translate(myRand(\_W, \_W\*2), myRand(0, \_H));  
  

I have changed the “circle:translate” to circle.translate(circle, etc…

in a couple of places in your code and set to 60 fps in config.lua

It seems to help alot…even tho they both are the same call…??? go figure…
You may want to try this and see if you notice…:wink:

EDIT: seem that Java uses the . operater vs the : (direct call)

Hope that helps…
Larry
“Follow Your Dreams!” [import]uid: 107633 topic_id: 21203 reply_id: 84212[/import]

Thanks Larry I’ll give it a go but would seem very odd as the API state object:translate (http://developer.anscamobile.com/reference/index/objecttranslate)

For reference by config.lua is

[lua]application = {
content = {
width = 320,
height = 480,
scale = “zoomEven”,
fps = 60,

–[[
imageSuffix = {
["@2x"] = 2,
}
–]]
}
}[/lua] [import]uid: 103970 topic_id: 21203 reply_id: 84217[/import]

I’ve tried and I can’t tell an improvement (maybe a slight FPS uplift) but at the point the circles go off screen and get redeploy at a starting position there seems to be a stutter / slight pause in the frame rate before smoothing out again [import]uid: 103970 topic_id: 21203 reply_id: 84219[/import]

Hi AParachutingFrog,

You should also check out my blog post for Cannon Cat http://cannoncat.tumblr.com/post/16869483296/corona-optimization I go over all the tricks I’m using for Cannon Cat.

As for why you’re seeing stuttering on occasion my guess is due to something going on with the GC.

Also you’re storing the math.random function into a local incorrectly it should be outside of the loop while in the function. Why do you need 3 listeners for enterFrame?

Make it one and have it call the other 3 functions. Less is faster. And why even have 3 functions? Have 1 that accomplishes all 3.

Functions should IMO only be used for reusability, and maybe in some cases avoided if speed is an issue.

I’m assuming you’re testing on your desktop or laptop. I think you’ll be hard pressed to get that speed on device. [import]uid: 27183 topic_id: 21203 reply_id: 84220[/import]

Thanks Don some really helpful tips and your game looks great I’ll certainly be checking it out.

I have refactored and optimised to the following:

[lua]local circles = {}
local stars = {}

– initial vars
local stars_total = 300
local stars_field1= 100
local stars_field2= 200
local stars_field3= 400
local star_width = 1
local star_height = 1

lowerStarfield = 1.4
middleStarfield = 2
upperStarfield = 3
circleCount = 10

local fps = require(“fps”)
local performance = fps.PerformanceOutput.new();
performance.group.x, performance.group.y = 0.5 * display.contentWidth, 0;
performance.alpha = 0.6; – So it doesn’t get in the way of the rest of the scene

_H = display.contentHeight
_W = display.contentWidth

local myRand = math.random

– create/draw objects
for i = 1, stars_total do
local star = {}

star.object = display.newRect(myRand(_W),myRand(_H),star_width,star_height)
if (i <= stars_field1) then
star.object:setFillColor(100,100,100)
elseif (i <= stars_field2 and i > stars_field1) then
star.object:setFillColor(155,155,155)
elseif(i <= stars_field3 and i > stars_field2) then
star.object:setFillColor(255,255,255)
end
stars[i] = star

star = nil
end

function updatePositioning(position, speed)
stars[position].object:translate(-speed ,0)

if (stars[position].object.x < 0) then
stars[position].object:translate(_W ,0)
end
end

local doStuff = function()
– Update the number of circles
if(#circles < circleCount) then
local circle = display.newImageRect(“circle.png”, 64, 64)
circle:translate(myRand(_W, _W*2), myRand(0, _H))
circle.name = “middle”
circle.index = #circles + 1

circles[circle.index] = circle
circle = nil
end

– Update the number of circles
for i = #circles,1, -1 do
local circle = {}
circle = circles[i]
circle:translate(-middleStarfield,0)
if(circle.x <= -20) then
circle.x = myRand(_W, _W+200)
circle.y = myRand(0, _H)
print(“x”, circle.x)
print(“y”, circle.y)
end

circles[i] = circle
circle = nil
end

for i = stars_total,1, -1 do
if (i <= stars_field1) then
updatePositioning(i, lowerStarfield)
elseif (i <= stars_field2 and i > stars_field1) then
updatePositioning(i, middleStarfield)
elseif(i <= stars_field3 and i > stars_field2) then
updatePositioning(i, upperStarfield)
end
end
end

Runtime:addEventListener( “enterFrame” , doStuff)
[/lua]

Whats interesting is that I am able now to achieve 60 fps however there are still significant pauses. The two main areas which you suggested in your blog focused on features that Spriteloq gave you but from what I read one of the display object caching happens automatically and shouldn’t be significant given the simplicity of the demo code I have written.

My concern is how to optimise this further to ensure the experience is smooth. Not sure where to take it given the little amount that is going on.

Further advice and assistance would be appreciated as have tested in both simulator and device now and still not happy with the results [import]uid: 103970 topic_id: 21203 reply_id: 84270[/import]

Done a bit of further digging and started using the excellent Corona Profiler.

What it has shown me that the updating of the stars is over 38% of total processing time of which half of this is the line
[lua]stars[position].object:translate(-speed ,0)[/lua]

Also a direct comparison within the conditional the the direct objects x position makes a further 35%

[lua]if (stars[position].object.x < 0) then[/lua]

If I take out the star processing this line takes up 22% of total processing

[lua]if(circle.x <= -20) then[/lua]

So it would seem accessing such properties has an adverse performance hit. But how would you optimise such logic? [import]uid: 103970 topic_id: 21203 reply_id: 84288[/import]

As noted in the optimization forum posts and my blog post property accesses are slow on display objects. You should cache those values and operate on the cached versions. Check out the Spriteloq API library loq_util’s loq_display function to see how I’m doing it there.

You should see a speed boost. Not sure about the stuttering, but you have all my tips, if I go any further I’d probably have to start charging for my time. :slight_smile: [import]uid: 27183 topic_id: 21203 reply_id: 84293[/import]

I am slowly going mad I think. Thank you ever so much to Don and Larry for their advice to date it has been invaluable and have learnt so much. However, despite getting my code up to 60fps and reducing the total milliseconds required to calculate the effort I still get stuttering graphics on both simulator and device.

This is becoming a real problem for me with such a simple example. I have reduced my code by over 40% and think I have implemented all the optimisation tips correctly because as I said Im achieving 60 fps .

I have refactored the code to use two different methods. The second, using transition.to, isn’t fully implemented but enough for me to profile to see if it makes a difference and eradicate the stutter / pausing graphics.

The first is my optimised original code

[lua]local circles = {}
local stars = {}
local starsCached = {}

– initial vars
local stars_total = 300
local stars_field1= 100
local stars_field2= 200
local stars_field3= 400
local star_width = 1
local star_height = 1

lowerStarfield = 1.4
middleStarfield = 2
upperStarfield = 3
circleCount = 10

_H = display.contentHeight
_W = display.contentWidth

local myRand = math.random

– create/draw objects

for i = 1, stars_total do
local star = {}

local _X = myRand(_W)
local _Y = myRand(_H)

star.object = display.newRect(_X,_Y,star_width,star_height)
star.object.cx = _X
star.object.cy = _Y

if (i <= stars_field1) then
star.object:setFillColor(100,100,100)
elseif (i <= stars_field2 and i > stars_field1) then
star.object:setFillColor(155,155,155)
elseif(i <= stars_field3 and i > stars_field2) then
star.object:setFillColor(255,255,255)
end
stars[i] = star
star = nil
end

function updatePositioning(position, speed)
stars[position].object.cx = stars[position].object.cx - speed

stars[position].object:translate(-speed ,0)

if (stars[position].object.cx < 0) then
stars[position].object:translate(_W ,0)
stars[position].object.cx = stars[position].object.cx + _W
end
end

local gameLoop = function()
– Update the number of circles
if(#circles < circleCount) then
local _X = myRand(_W, _W*2)
local _Y = myRand(0, _H)
local circle = display.newImageRect(“circle.png”, 64, 64)
circle:translate(_X, _Y)
circle.cx = _X
circle.cy = _Y
circle.name = “middle”
circle.index = #circles + 1

circles[circle.index] = circle
circle = nil
end

– Update the number of circles
for i = #circles,1, -1 do
local circle = {}
circle = circles[i]
print(circle.cx)
circle.cx = circle.cx - middleStarfield
circle:translate(-middleStarfield,0)
if(circle.cx <= -20) then
circle.cx = myRand(_W, _W+200)
circle.cy = myRand(0, _H)
circle.x = circle.cx
circle.y = circle.cy
end

circles[i] = circle
circle = nil
end

for i = stars_total,1, -1 do
if (i <= stars_field1) then
updatePositioning(i, lowerStarfield)
elseif (i <= stars_field2 and i > stars_field1) then
updatePositioning(i, middleStarfield)
elseif(i <= stars_field3 and i > stars_field2) then
updatePositioning(i, upperStarfield)
end
end
end
Runtime:addEventListener( “enterFrame” , gameLoop)[/lua]

The second is using transition.to to see if the lack of intervention makes a difference

[lua]local circles = {}
local stars = {}
local starsCached = {}

– initial vars
local stars_total = 500
local stars_field1= 200
local stars_field2= 400
local stars_field3= 800
local star_width = 1
local star_height = 1

lowerStarfield = 1.4
middleStarfield = 2
upperStarfield = 3
circleCount = 10

_H = display.contentHeight
_W = display.contentWidth

local myRand = math.random

local delta = 10000 / 480
– create/draw objects

local listener2= function( obj )
local _X = myRand(_W, _W*2)
local _Y = myRand(0, _H)
local milli = (_X -480) * delta
obj.y = _Y
obj.x = _X

transition.to( obj, { time=(_X * delta)* 1.2, x=-30, onComplete=listener2 } )

end

local listener3= function( obj )
local _X = myRand(_W, _W*2)
local _Y = myRand(0, _H)
local milli = (_X -480) * delta
obj.y = _Y
obj.x = _X

transition.to( obj, { time=(_X * delta)* 0.9, x=-30, onComplete=listener3 } )

end

local listener4= function( obj )
local _X = myRand(_W, _W*2)
local _Y = myRand(0, _H)
local milli = (_X -480) * delta
obj.y = _Y
obj.x = _X

transition.to( obj, { time=(_X * delta) * 0.7, x=-30, onComplete=listener4 } )

end

local listener1 = function( obj )
local _X = myRand(_W, _W*2)
local milli = (_X -480) * delta
local _Y = myRand(0, _H)
obj.y = _Y
obj.x = _X

transition.to( obj, { time=(10000 + milli), x=-30, onComplete=listener1 } )

end

for i = 1, stars_total do
local star = {}

local _X = myRand(_W)
local _Y = myRand(_H)
local milli = (_X -480) * delta

star.object = display.newRect(_X,_Y,star_width,star_height)
star.object.cx = _X
star.object.cy = _Y

if (i <= stars_field1) then
star.object:setFillColor(100,100,100)
transition.to( star.object, { time=(_X * delta)* 1.2, x=-30, onComplete=listener2 } )
elseif (i <= stars_field2 and i > stars_field1) then
star.object:setFillColor(155,155,155)
transition.to( star.object, { time=(_X * delta)* 0.9, x=-30, onComplete=listener3 } )
elseif(i <= stars_field3 and i > stars_field2) then
star.object:setFillColor(255,255,255)
transition.to( star.object, { time=(_X * delta) * 0.7, x=-30, onComplete=listener4 } )
end
stars[i] = star
star = nil
end
local gameLoop = function()
– Update the number of circles
if(#circles < circleCount) then
local _X = myRand(_W, _W*2)
local milli = (_X -480) * delta
local _Y = myRand(0, _H)
local circle = display.newImageRect(“circle.png”, 64, 64)
–circle:translate(_X, _Y)
circle.x = _X
circle.y = _Y
transition.to( circle, { time=(10000 + milli), x=-30, onComplete=listener1 } )
circle.name = “middle”
circle.index = #circles + 1

circles[circle.index] = circle
circle = nil
end

– Update the number of circles

end
Runtime:addEventListener( “enterFrame” , gameLoop)[/lua]

I am using the incredibly useful Corona Profiler by M.Y. Developers to analyse hot spots which I think I have but the performance just doesn’t seem to be there. Any help or advice would be greatly appreciated and I’m sure invaluable to any newbie like me who is delving into the complex world of optimisation.

J

P.S. free advice please as Don no I can’t afford your expertise :slight_smile: [import]uid: 103970 topic_id: 21203 reply_id: 84693[/import]

Hi

Thought I’d share my findings. Essentially I have managed to resolve the stuttering by doing a couple of things

The first is moving the following code outside of the game event loop

[lua]if(#circles < circleCount) then
local _X = myRand(_W, _W*2)
local _Y = myRand(0, _H)
local circle = display.newImageRect(“circle.png”, 64, 64)
circle:translate(_X, _Y)
circle.cx = _X
circle.cy = _Y
circle.name = “middle”
circle.index = #circles + 1

circles[circle.index] = circle
circle = nil
end[/lua]

The reason why this is acceptable is that the type of spawning I am doing I can offset the x position with a suitable delay up front and then when off screen recalculating so it doesn’t therefore need to do the creation check 60 times a second as I had in the above example.

Additionally, the number of star objects (800) were too many for the device to handle despite all optimisation implemented. This is understandable given if this were an enemy etc you perhaps wouldn’t expect quite so many.

All in all though this process has been very worthwhile and now have a smooth animation and frame rates around 60 fps!

Hope this helps somebody :slight_smile: [import]uid: 103970 topic_id: 21203 reply_id: 84833[/import]

Hello ParachutingFrog,
We are happy to see our software helped you optimize your code! If we saw this post earlier we would have helped you fix your issue. We wanted to share our experiences with optimizing space conquest as we think there is a common performance issue that can be fixed rather easily and it applies to your situation.

  1. First of all identify the lines of code that are slow.
  2. Think to yourself, Do I really need to run these every frame or can I get away with doing it every 10 frames?
    -Probably our most significant performance breakthrough came from this realization. The fact that you are calling a function (even an empty one) requires quite a bit of CPU power if it is called often. Think about it, you need to save the stack, save the registers, save the cpu state and then reload all these when you return from a function. It may look elegant to call an act() function for every object in every frame, but often times elegant does not necessarily mean fast. In short, call as few functions as possible, it may look uglier but try to un-factor functions if you can, if it is in a loop. We almost never call a function in a critical game loop.
    3) Next see if this fixes your problem before you do further unnecessary optimization. We cannot agree more with Don’s suggestions. It may seem counter-intuitive at times but if you can use the physics engine, use it! its much faster than Lua code since its written in C. Also, if things have gone off screen don’t draw it.
    4) Don’t assume anything, profile it first. We found that using a lookup table for the trigonometric functions was actually slower than the standard functions! Crazy but true.

    Thanks,
    M.Y. Developers [import]uid: 55057 topic_id: 21203 reply_id: 85668[/import]