Hey guys - as Josh mentioned, he hasn’t been able to reproduce. So we would need to get your project (or a subset of it) that shows the issue.
Feel free to email me directly (david AT coronalabs) to arrange this.
Hey guys - as Josh mentioned, he hasn’t been able to reproduce. So we would need to get your project (or a subset of it) that shows the issue.
Feel free to email me directly (david AT coronalabs) to arrange this.
Hey guys,
I’ll try to send you a subset of the project as soon as possible. Meanwhile, if you want to take a look on the app, here is the link to it one on the Windows Phone store.
http://www.windowsphone.com/en-us/store/app/solitaire-premium/00afedc8-a9a1-4e1f-8dc3-140f016da0f3
This is the game that we the delay is more noticeable, but it still happens in varying degrees on all apps. We have done our tests on a Lumia Nokia 520.
I just downloaded and played with your app now. I can definitely see the slowness issue that you’re talking about… but I’m thinking that it might be caused by the timer text object you have in the top-right corner. If you’re using that “Font-Manager” bitmap library to update that text, then that might be the cause. Try disabling the text updates in the top right corner to confirm that this is the issue.
Thanks David/Joshua - it’s a bit hectic here as we’re in the middle of iOS/Android submissions at the moment, but once we’re back onto WP8 again I’ll send over the project.
Hey Joshua,
We are not using the Font-Manager lib. There was an old bitmap font lib on the Corona Projects that we refactored / improved to make it compatible with graphics 2.0 and our own custom libraries. But I did find some answers to the problem.
While cutting parts of the project away to send to you guys, I noticed that the drag issue was getting better. Then, following your suggestion about the timer, Isaw that it was being updated more frequently than it should. Reducing the update time also solved the drag problem, even keeping most of the project intact.
My guess is that it wasn’t a single part of the project that was causing the delay, just that the device was indeed “overloaded” and could not process the input fast enough. In the previous tests I was too focused on the event part, trying to find what could be causing it and ended up missing what was happening on the rest of the project.
Well, I’ll do some more tests on the other games to see what we change to improve performance and see if we have similar results. If I find anything that seems weird I’ll keep you posted.
Thanks for the help!
Happy to help!
And yeah, if you find anything weird, please feel free to let us know.
I’m surprised to see this topic, because I’m experiencing the total opposite, my touch events have a 3 second (approx) delay when I try to drag an object.
I’m testing on a Nokia 920, and generally I get about 30fps depending on how much is happening on screen. I’ve actually disabled most of the text and print statements to see if this improved things, but it made no difference (I should specify that it did speed up places where text is created).
In our game you can drag the gameplay area to move around, and also there is a pulldown menu at the top of the screen. On iOS and Android these both work fine, but on WP8 if I touch the menu, drag down and then release the “began”, “moved” and “ended” phases only show up after about 3 seconds (I’m printing them out to check when they happen).
The same goes for the gameplay area, if I drag and then release I have to wait for anything to happen which makes the game seem unresponsive, so you end up dragging again thinking it hasn’t worked.
Have I missed something that could be causing this to happen? I’m not going to claim to be an expert at WP8 development, as this is the first app we’ve tried to port, so any advice would be helpful.
Thanks
Hey! I happen to be in the middle of writing an article on this, but I’ll dump some code here to help with this problem.
The issue you are seeing is that, touches are not processed frame-synchronous but rather (I assume) in real-time.
This allows for multiple move events (from the same source) to occur per frame.
If you are doing heavy calculations based on this input, you will see performance dips in your game/app.
To fix this, you need to do what I call, ‘touch coalescing’.
The following two code samples will demonstrate the difference.
Run the samples below and quickly touch and drag your finger across the screen to see the issue.
Without Coalescing:
local enableShow = true local events = {} local group = display.newGroup() local circle local rect = display.newRect( display.contentCenterX, display.contentCenterY, display.actualContentWidth, display.actualContentHeight ) rect:setFillColor(0.2,0.2,0.2) local function showEvents() if( not enableShow ) then return end display.remove(group) group = display.newGroup() local y = 10 for i = 1, #events do local event = events[i] local tmp1 = display.newText( group, event.phase, 10, y, native.systemFont, 8 ) local tmp2 = display.newText( group, "@ " .. event.time, 100, y, native.systemFont, 8 ) tmp1.anchorX = 0 tmp2.anchorX = 0 tmp2:setFillColor(0,0,0) if( event.phase == "enterFrame" ) then tmp1:setFillColor(1,0,1) elseif( event.phase == "began" ) then tmp1:setFillColor(1,0,0) elseif( event.phase == "moved" ) then tmp1:setFillColor(0,1,0) elseif( event.phase == "ended" ) then tmp1:setFillColor(0,0,1) else tmp1:setFillColor(0,0,0) end y = y + 10 end events = {} end rect.enterFrame = function( self, event ) event.phase = "enterFrame" events[#events+1] = event end rect.touch = function( self, event ) if( event.phase == "began" ) then events[#events+1] = event Runtime:addEventListener( "enterFrame", self ) circle = display.newCircle( event.x, event.y, 20 ) elseif( event.phase == "ended" ) then events[#events+1] = event Runtime:removeEventListener( "enterFrame", self ) showEvents() display.remove(circle) else events[#events+1] = event circle.x = event.x circle.y = event.y end return true end rect:addEventListener( "touch" )
With Coalescing:
local enableShow = true local events = {} local group = display.newGroup() local circle local rect = display.newRect( display.contentCenterX, display.contentCenterY, display.actualContentWidth, display.actualContentHeight ) rect:setFillColor(0.2,0.2,0.2) local function showEvents() if( not enableShow ) then return end display.remove(group) group = display.newGroup() local y = 10 for i = 1, #events do local event = events[i] local tmp1 = display.newText( group, event.phase, 10, y, native.systemFont, 8 ) local tmp2 = display.newText( group, "@ " .. event.time, 100, y, native.systemFont, 8 ) tmp1.anchorX = 0 tmp2.anchorX = 0 tmp2:setFillColor(0,0,0) if( event.phase == "enterFrame" ) then tmp1:setFillColor(1,0,1) elseif( event.phase == "began" ) then tmp1:setFillColor(1,0,0) elseif( event.phase == "moved" ) then tmp1:setFillColor(0,1,0) elseif( event.phase == "ended" ) then tmp1:setFillColor(0,0,1) else tmp1:setFillColor(0,0,0) end y = y + 10 end events = {} end \_G.FRAME\_COUNT = 0 local function frameCounter() FRAME\_COUNT = FRAME\_COUNT + 1 end Runtime:addEventListener( "enterFrame", frameCounter ) rect.enterFrame = function( self, event ) event.phase = "enterFrame" events[#events+1] = event end rect.touch = function( self, event ) if( event.phase == "began" ) then events[#events+1] = event Runtime:addEventListener( "enterFrame", self ) circle = display.newCircle( event.x, event.y, 20 ) self.\_lastFrame = FRAME\_COUNT elseif( event.phase == "ended" ) then events[#events+1] = event Runtime:removeEventListener( "enterFrame", self ) showEvents() display.remove(circle) elseif( FRAME\_COUNT \> self.\_lastFrame ) then events[#events+1] = event circle.x = event.x circle.y = event.y self.\_lastFrame = FRAME\_COUNT end return true end rect:addEventListener( "touch" )
Again, I’m in the middle of writing an article on this, so if I get it accepted you should see a more detailed description in the blog.
@roaminggamer is right. You will receive multiple touch events between frames on WP8. The same is true on Android. This is actually a good thing because it ensure that no touch events get missed/dropped by your app. Especially if you want to implement gesture controls.
But that said, odds are your probably have a text object update somewhere in your code. The majority of performance issues that occur to WP8 developers is due to frequent text updates/creation. Make sure that you are not indirectly updating text either, such as via our widget library which uses text objects internally. Other than that, 60 FPS is absolutely possible on WP8. Even with touch and drag events going on. Us getting 60 FPS working with a silverlight based WP8 app is actually one of our crowning achievement that other WP8 native developers struggle with. So, don’t lose hope. :)
I actually removed all text by overriding the display.newText function so that it just drew rects instead, so there is no ‘real’ text in game. Likewise I don’t think there are any widgets using text, and I’ve overridden the print function too so there should be no slow string operations there either.
I’ll take a look at @roaminggamer’s suggestion in the morning and see if that improves things.
Thanks
I had to take a break from WP8 while fixing some things for other platforms, but I’ve taken another look. In @roaminggamer’s approach it seems that you are simply storing all of the events, and then processing them all at once in the frame update. Makes sense given the nature of the problem, though it seemed to me that it would get complicated when hacing to take into account simultaneous touches (not impossible I’m sure, but certainly more difficult).
I tried something slightly simpler as an experiment:
local touchIDs = {} local r = display.newRect(0, 0, display.contentWidth, display.contentHeight) r:setFillColor(0.5, 0, 0) local lastX, lastY = nil, nil function r:touch(e) if e.phase == "began" then lastX, lastY = e.x, e.y elseif e.phase == "moved" then if touchIDs[e.id] then print("already moved this frame") return end touchIDs[e.id] = true r.x, r.y = r.x + (e.x - lastX), e.y + (e.y - lastY) lastX, lastY = e.x, e.y elseif e.phase == "ended" or e.phase == "cancelled" then touchIDs[e.id] = nil end return true end r:addEventListener("touch", r) local function update(e) touchIDs = {} print("reset touches") end Runtime:addEventListener("enterFrame", update)
This only allows one “moved” event per frame - not ideal for scrolling but I just wanted to see what would happen. It worked as expected: if a touch id had already moved in a frame, it would not move until the next frame when the table tracking the touches was reset.
In the sample with just one red rect to scroll around the screen, and nothing else loaded (no text, no images, no audio) the frame rate ranged from 45-60 when nothing was happening, and would range from ~22-45 when scrolling. Not a constant 60fps, but certainly good enough to play. I found it curious that the fps did drop even when the game consists of one object, but when it dropped to 22fps it was a spike every 10 frames or so rather than a prolonged drop. In my own game, the frame rate drops to 3 or 4fps when touching, from 45+ when not touching.
Since text seems to be a major problem for people, I thought I’d try and see if I can change something to do with that. As I’ve mentioned in a previous post, I’ve tried overwriting the newText function so that all calls to display.newText actually draw rects instead (it was the easiest way I could think of to remove all text with removing all calls in my code). At any given time there can be upto ~50 text objects in memory in my game (not necessarily all on screen at the same time) so if text was the issue I figured that might work. I put the function overwrite code back in and still only got ~4fps when scrolling.
I then changed the sample project so it would scroll a group, and added 50 text objects to it. The frame rate was the same as with no text objects (~22-45). So then I tried 50, 200, 500 and 1000 text objects. All on screen at the same time, and the frame rate was still higher when scrolling than in my game with all text objects removed. Admittedly it got progressively slower but with 1000 text objects on screen I still got ~15fps when scrolling their group, which is 3-5 times higher than in my own game.
Just before I was about to post this, I did another test in my actual game. I completely commented out all of the code in my “moved” phase, other than the part where I track the touch IDs. So there are no calculations, no x/y movements, no scaling…nothing happening other than setting a few bools to true or false. I also only used one finger. I regularly had 100+ moved events fired in a single frame!
Presumably that means that there is something inherently slowing down the frame time. Is there anything else that is known to cause major performance issues? As I say, even with a single rect the fps dropped when scrolling.
Any help would be greatly appreciated. I’m well aware that I could have overlooked something which would fix this, and since others seem to be able to get good frame rates I’m hoping someone can help.
Alan,
You should also know that running your WP8 app via the Visual Studio debugger will severely impact the framerate too. As in you can’t get 60 FPS while running your app via the debugger. You definitely can’t get 60 FPS in the WP8 emulator either. For best performance, you need to build a “Release|ARM” version of your app, deploy it to your WP8 device (you can use Visual Studio’s Debug/Run button), stop the Visual Studio debugger, and then run the app normally by tapping on it.
I have a low-end WP8 device (a Nokia Lumia 620) that can run the above at a clean 60 FPS.
I do however have another WP8 device (a Nokia Lumia 920) that never gets 60 FPS in a Silverlight app (hovers around 45-55 FPS) and have concluded that its a device specific issue. I’ve concluded this by making a native Silverlight app *without* Corona (based on Microsoft’s Silverlight Direct3D project template) and discovered that Microsoft’s rendering thread would render late every 4th frame. And this is me rendering absolutely nothing, just a black screen, and it’s getting a 45-50 framerate. There’s nothing we can do about that since it’s out of our control. So, some WP8 devices will never give you 60 FPS. You *might* have one of those devices.
I have a Nokia 920 so that could be it. And thanks for the other pointers, I’ll try them out and see what happens. I figured the debugger would have some impact, but didn’t realise it would be that bad.
Happy to help.
I think the debugger is loads better compared to Xcode’s, but yeah, I’m thinking it was designed more for debugging normal apps. Still comes in handy for games though if you need to track down a crash, memory leak, etc. I also find that running a debug version of your app without the debugger runs pretty fast as well, but a release build will be a bit faster. Especially on startup since the built app will be smaller (no debug symbols compiled in).
Also, some WP8 developers told me that updating their device’s operating system from 8.0 to 8.1 improved the framerate for them, suggesting that 8.1 provided some performance improvements, but that wasn’t the case for my Lumia 920.
Hello again,
We were doing some more tests, trying to find ways to improve our performance. In general our framerate seem to be ok, not dropping too much, but in some games the touch seemed unresponsive/laggy.
We ran some test, printing the phase of the touch event, followed by the time it occured (using system.getTimer) and the difference to the previous one. This is what we got (each touch is separted by a ========):
========== Phase: began, Time: 13344 Phase: moved, Time: 13620, Diff: 276 Phase: moved, Time: 13621, Diff: 1 Phase: moved, Time: 13621, Diff: 0 Phase: moved, Time: 13623, Diff: 2 Phase: moved, Time: 13624, Diff: 1 Phase: moved, Time: 13625, Diff: 1 Phase: moved, Time: 13627, Diff: 2 Phase: moved, Time: 13628, Diff: 1 Phase: ended, Time: 13629, Diff: 1 ========== ========== Phase: began, Time: 17783 Phase: moved, Time: 18061, Diff: 278 Phase: moved, Time: 18062, Diff: 1 Phase: moved, Time: 18063, Diff: 1 Phase: moved, Time: 18064, Diff: 1 Phase: moved, Time: 18065, Diff: 1 Phase: moved, Time: 18066, Diff: 1 Phase: moved, Time: 18067, Diff: 1 Phase: moved, Time: 18067, Diff: 0 Phase: moved, Time: 18068, Diff: 1 Phase: moved, Time: 18069, Diff: 1 Phase: moved, Time: 18070, Diff: 1 Phase: moved, Time: 18072, Diff: 2 Phase: moved, Time: 18073, Diff: 1 Phase: moved, Time: 18074, Diff: 1 Phase: moved, Time: 18076, Diff: 2 Phase: moved, Time: 18193, Diff: 117 Phase: moved, Time: 18194, Diff: 1 Phase: moved, Time: 18196, Diff: 2 Phase: moved, Time: 18198, Diff: 2 Phase: moved, Time: 18199, Diff: 1 Phase: moved, Time: 18200, Diff: 1 Phase: moved, Time: 18200, Diff: 0 Phase: moved, Time: 18201, Diff: 1 Phase: moved, Time: 18202, Diff: 1 Phase: moved, Time: 18203, Diff: 1 Phase: moved, Time: 18204, Diff: 1 Phase: moved, Time: 18204, Diff: 0 Phase: moved, Time: 18206, Diff: 2 Phase: moved, Time: 18327, Diff: 121 Phase: moved, Time: 18329, Diff: 2 Phase: moved, Time: 18330, Diff: 1 Phase: moved, Time: 18331, Diff: 1 Phase: moved, Time: 18332, Diff: 1 Phase: moved, Time: 18333, Diff: 1 Phase: moved, Time: 18334, Diff: 1 Phase: moved, Time: 18334, Diff: 0 Phase: moved, Time: 18335, Diff: 1 Phase: moved, Time: 18336, Diff: 1 Phase: moved, Time: 18337, Diff: 1 Phase: moved, Time: 18338, Diff: 1 Phase: moved, Time: 18339, Diff: 1 Phase: moved, Time: 18403, Diff: 64 Phase: moved, Time: 18404, Diff: 1 Phase: moved, Time: 18405, Diff: 1 Phase: moved, Time: 18407, Diff: 2 Phase: moved, Time: 18409, Diff: 2 Phase: moved, Time: 18410, Diff: 1 Phase: moved, Time: 18412, Diff: 2 Phase: moved, Time: 18523, Diff: 111 Phase: moved, Time: 18524, Diff: 1 Phase: moved, Time: 18525, Diff: 1 Phase: moved, Time: 18526, Diff: 1 Phase: moved, Time: 18528, Diff: 2 Phase: moved, Time: 18529, Diff: 1 Phase: ended, Time: 18529, Diff: 0 ========== ========== Phase: began, Time: 90336, Diff: 0 Phase: moved, Time: 90338, Diff: 2 Phase: moved, Time: 90552, Diff: 214 Phase: moved, Time: 90553, Diff: 1 Phase: moved, Time: 90554, Diff: 1 Phase: ended, Time: 90555, Diff: 1 ========== ========== Phase: began, Time: 104438, Diff: 0 Phase: moved, Time: 104440, Diff: 2 Phase: moved, Time: 104641, Diff: 201 Phase: moved, Time: 104642, Diff: 1 Phase: moved, Time: 104644, Diff: 2 Phase: moved, Time: 104645, Diff: 1 Phase: moved, Time: 104647, Diff: 2 Phase: moved, Time: 104649, Diff: 2 Phase: moved, Time: 104649, Diff: 0 Phase: moved, Time: 104652, Diff: 3 Phase: moved, Time: 104653, Diff: 1 Phase: moved, Time: 104653, Diff: 0 Phase: moved, Time: 104655, Diff: 2 Phase: moved, Time: 104801, Diff: 146 Phase: moved, Time: 104802, Diff: 1 Phase: moved, Time: 104802, Diff: 0 Phase: moved, Time: 104803, Diff: 1 Phase: moved, Time: 104804, Diff: 1 Phase: moved, Time: 104805, Diff: 1 Phase: moved, Time: 104806, Diff: 1 Phase: moved, Time: 104806, Diff: 0 Phase: moved, Time: 104808, Diff: 2 Phase: moved, Time: 104809, Diff: 1 Phase: moved, Time: 104811, Diff: 2 Phase: moved, Time: 104813, Diff: 2 Phase: moved, Time: 104814, Diff: 1 Phase: moved, Time: 104815, Diff: 1 Phase: moved, Time: 104816, Diff: 1 Phase: moved, Time: 104817, Diff: 1 Phase: moved, Time: 104889, Diff: 72 Phase: moved, Time: 104890, Diff: 1 Phase: moved, Time: 104891, Diff: 1 Phase: moved, Time: 104893, Diff: 2 Phase: moved, Time: 104895, Diff: 2 Phase: moved, Time: 104896, Diff: 1 Phase: moved, Time: 104897, Diff: 1 Phase: moved, Time: 104899, Diff: 2 Phase: moved, Time: 104975, Diff: 76 Phase: moved, Time: 104976, Diff: 1 Phase: moved, Time: 104979, Diff: 3 Phase: moved, Time: 104980, Diff: 1 Phase: moved, Time: 104980, Diff: 0 Phase: moved, Time: 104982, Diff: 2 Phase: moved, Time: 104983, Diff: 1 Phase: moved, Time: 104984, Diff: 1 Phase: moved, Time: 105058, Diff: 74 Phase: moved, Time: 105059, Diff: 1 Phase: moved, Time: 105060, Diff: 1 Phase: moved, Time: 105061, Diff: 1 Phase: moved, Time: 105063, Diff: 2 Phase: moved, Time: 105065, Diff: 2 Phase: moved, Time: 105066, Diff: 1 Phase: moved, Time: 105068, Diff: 2 Phase: moved, Time: 105252, Diff: 184 Phase: moved, Time: 105252, Diff: 0 Phase: moved, Time: 105254, Diff: 2 Phase: moved, Time: 105255, Diff: 1 Phase: moved, Time: 105256, Diff: 1 Phase: moved, Time: 105256, Diff: 0 Phase: moved, Time: 105257, Diff: 1 Phase: moved, Time: 105258, Diff: 1 Phase: moved, Time: 105259, Diff: 1 Phase: moved, Time: 105260, Diff: 1 Phase: moved, Time: 105261, Diff: 1 Phase: moved, Time: 105262, Diff: 1 Phase: moved, Time: 105263, Diff: 1 Phase: moved, Time: 105264, Diff: 1 Phase: moved, Time: 105266, Diff: 2 Phase: moved, Time: 105266, Diff: 0 Phase: moved, Time: 105268, Diff: 2 Phase: moved, Time: 105269, Diff: 1 Phase: moved, Time: 105270, Diff: 1 Phase: moved, Time: 105444, Diff: 174 Phase: moved, Time: 105446, Diff: 2 Phase: moved, Time: 105446, Diff: 0 Phase: moved, Time: 105447, Diff: 1 Phase: moved, Time: 105448, Diff: 1 Phase: moved, Time: 105449, Diff: 1 Phase: moved, Time: 105450, Diff: 1 Phase: moved, Time: 105450, Diff: 0 Phase: moved, Time: 105451, Diff: 1 Phase: moved, Time: 105452, Diff: 1 Phase: moved, Time: 105453, Diff: 1 Phase: moved, Time: 105453, Diff: 0 Phase: moved, Time: 105454, Diff: 1 Phase: moved, Time: 105455, Diff: 1 Phase: moved, Time: 105456, Diff: 1 Phase: moved, Time: 105456, Diff: 0 Phase: ended, Time: 105457, Diff: 1 ==========
It seems that between some moved events we are getting a big delay, upwards to 100 ms, and this seems more pronounced close to the initial “began” event. It this delays occurred close to enterFrame events so it seems that it may be affecting the touch events.
Any ideas on how to workaround this ?
Well, it’s not the touch events the is causing lag in your app. It’s what you do within your touch listener is likely the culprit. Or perhaps it may have nothing to do with your touch listeners and you have some other operations in the background, such as multiple large network.request() operations that is dominating the poor slow dual core CPU and preventing the main UI thread or Direct3D rendering thread from getting invoked on time.
So, you said 1 app of yours has this problem and another doesn’t. What features are they using? What are they doing differently?
Odds are this is not touch related… just that touching and dragging makes latency issues much more noticeable.
Just catching up on the forum and saw this so had some ideas.Not sure if this will work as just typing it from my head. Sorry about the formatting all the tabs vanish lol
[lua]
-----------------------IDEA 1
local allow=true;
local function touchFunction(event)
if allow==true then
if event.phase==“moved” then
allow=false;
–do something
timer.performWithDelay(17,function()allow=true;end);
end
end
end
yourObject:addEventListener(“touch”,touchFunction)
-----------------------IDEA 2
local allow=true;
local function touchFunction(event)
if allow==true then
if event.phase==“moved” then
allow=false;
–do something
end
end
end
yourObject:addEventListener(“touch”,touchFunction)
local function reEnable()
if allow==false then allow=true end
end
Runtime:addEventListener(“enterFrame”,reEnable)
[/lua]
Oh and I have a Nokia 925. Its very nice and runs between 45-60 fps which is just fine
oh and you could change the 17 milliseconds to 34 in idea 1 and see if that helps even more as this will be compatible with 30fps.
or just get fps and 1000/fps
I’ve heard that you are still have performance issues with you touch event. I’m wondering, are you updating text with the “Font-Manager” bitmap font library via your touch listeners? It’s come to my attention that the “Font-Manager” library has performance issues due to a lot of wasteful string parsing and regular expression it does every time you update a small amount of text. During my testing, I’ve discovered that updating a small amount of text via “Font-Manager” can take about 15-30 milliseconds. I shared my findings here…
http://forums.coronalabs.com/topic/53450-performance-problems-with-newtableview/?p=279041
So, if you are using the free “Font-Manager” library, then that might be the cause.
The “bmFont2” bitmap font library was a lot faster during my testing.
I haven’t tried “TextCandy” yet.