Performace assistance appreciated.

It’s on device only.
It’s still slowing down with ~10 enemies on screen.
On top on that it’s now crashing.
Such a huge shame I got this far. I’d put in thousands of hours of work over the last 5 or so years.
Thanks for the help but seems more of a lost cause now than it was a month ago.
:cry:

Have you tried debugging with logcat? When there’s a silent crash on device you can see the error message on logcat.

https://docs.coronalabs.com/guide/basics/debugging/index.html#device-debugging-android

1 Like

I’ll try and set it up tomorrow.
Thanks so much and goodnight.

1 Like

@DigiNick - @bgmadclown has given you the best advice. Using the print statement combined with being able to watch the log via ADB (Android) or CONSOLE (iOS) can help you find the problem, with certainty. It’s just a bug or something strange about the engine you aren’t realizing is causing the problem. Once you find where the problem is, and the relevant variables you can print just before it halts, you’ll have all you need to take this over the top. I’ve released 4 apps with a 5th to be released later this month; all with Corona SDK. I’ve also recently completed my first UPDATE using the Solar2D OFFLINE version 3598 with 100% success. You can do it. And here in our community, we’re all here to help you! This is one of the greatest developer communities I’ve ever known. Keep us all informed and remain determined; we’re all like your extended staff down the hallway; except that some of us are on the other side of the planet :slight_smile:

1 Like

Thanks very much.
I followed @bgmadclown’s link and found the option for neverStripDebugInfo - I’ve now been compiling with my release key for months so maybe that’s why I’ve not got the error messages.
Also, after downgrading my version yesterday I now have the option to deathorise, so might get offline builds running, but it’s currently not a priority.
What I need to do is stop the crashes and work out why, with a dozen enemies on screen I’m still getting slowdown. Literally as soon as kill half of them the framerate goes back to 30 so it’s still quite the headscratcher - and I don’t want to release in this state, especially as it’s my first game and kinda sets the standard for my work.
I will post again when I’ve learned more, and before I finish this thread will make a summary of what I’ve changed and how much it’s improved things.
Best wishes to you all.

If you’d like to share your code, I’d be happy to find what the problem is. Just send me a private message with the necessary files. But if you aren’t comfortable with that, I understand. Just know we’re here to help.

1 Like

Going to update now, as I am likely going to be too busy to take this much further over the near future.

Apart from what’s already been stated above, I’ve now also:

  • Added correct physics collisions filters. Before I had one (two including enemies) - I am now using 13 in total.
  • Created multiple object pools. I now load 100 objects into tables for things I use in spells - magebolts, exploding fragments, snow, impact markers, “spangles”, bubbles, goop splats, clouds of gas and lightning strikes. 1000 objects for particles used for different effects, tracers when you cast spells, and footprints left by enemies.

I can see from the stats that I was monitoring the following changes:

  • Collisions have gone from about 1500 per second peak to around 150.
  • Images created per second from 1000 peak to 12.
  • Sprites created per second from 650 peak to 4.
  • Transitions from 1000 per second peak to around 600.
  • Lua memory has gone from about 1800k to around 3500k, texture memory from 200Mb to 160Mb.

I cannot reduce transitions a whole lot more, without sacrificing the feel of the game.

This has sped up not only the FPS counter, but the game feels noticeably snappier when the spells actually manifest on screen. FPS drops to around 10 minimum when multiple enemies exist, it was around half that before. With everything I’ve done and how much better it feels, I can’t help but feel I’m so close to putting my finger on what is bogging it down with the enemies.

1 Like

For anyone else out there who needs it, here is the code I’ve used to get this far. As mentioned before, some of this has been given to me by posters above, so I can’t take all the credit for it:

local debugMode = {}
debugMode.debugLevel = 0
debugMode.toggleCount = 0

debugMode.statsCollision = function()
if debugMode.debugLevel > 0 then
		debugMode.collisions = debugMode.collisions + 1
	end
end
debugMode.statsImage = function()
	if debugMode.debugLevel > 0 then
		debugMode.images = debugMode.images + 1
	end
end
debugMode.statsSprite = function()
	if debugMode.debugLevel > 0 then
		debugMode.sprites = debugMode.sprites + 1
	end
end
debugMode.console = function(t)
	if debugMode.debugLevel > 0 then
		transition.cancel(debugMode.consoleText)
		debugMode.consoleText.alpha = 1
		debugMode.consoleText.x, debugMode.consoleText.y = 200, 200
		if t == debugMode.consoleMessage then
			debugMode.consoleCount = debugMode.consoleCount + 1
			debugMode.consoleText.text = t.." x"..debugMode.consoleCount
		else
			debugMode.consoleCount = 1
			debugMode.consoleMessage = t		
			debugMode.consoleText.text = t
		end
		transition.to(debugMode.consoleText, {delay=1000, time=1000, x=-500})	
		transition.from(debugMode.consoleText, {time=100, alpha=0, y=225})
	end
end

Then add debugMode.statsCollision() in collision handlers, Image/Sprite wherever you create one.

function debugMode.countFPS(event)
	debugMode.frames = debugMode.frames + 1
end
function debugMode.textColour(s, t, l, m, u)
	if s > u then
		setColour(t, "Red")
	elseif s > m then
		setColour(t, "Orange")
	elseif s > l then
		setColour(t, "Yellow")
	else
		setColour(t, "Green")
	end
end
function debugMode.setText(sMax, sMaxText, sMaxTimeText)
	sMaxText.text = "Max: "..sMax
	sMaxTimeText.text = Round(system.getTimer() * 0.001).."s"
end
function debugMode.Timer()
	debugMode.tmDebug = timer.performWithDelay(1000,
		function()
			if debugMode.frames < 5 then
				setColour(debugMode.fpsText, "Red")
			elseif debugMode.frames < 15 then
				setColour(debugMode.fpsText, "Orange")
			elseif debugMode.frames < 25 then
				setColour(debugMode.fpsText, "Yellow")
			else
				setColour(debugMode.fpsText, "Green")
			end
			debugMode.textColour(debugMode.collisions, debugMode.collisionsText, 250, 500, 1000)
			debugMode.textColour(debugMode.images, debugMode.imagesText, 250, 500, 1000)
			debugMode.textColour(debugMode.sprites, debugMode.spritesText, 250, 500, 1000)
			debugMode.textColour(#transition._transitionTable, debugMode.transitionsText, 250, 500, 1000)
			debugMode.collisionsText.text = "Collisions / s: "..debugMode.collisions
			debugMode.fpsText.text = "FPS: "..debugMode.frames
			debugMode.imagesText.text = "Images / s: "..debugMode.images
			debugMode.spritesText.text = "Sprites / s: "..debugMode.sprites
			debugMode.transitionsText.text =  "Transitions / s: "..#transition._transitionTable
			debugMode.texMem = Round(system.getInfo("textureMemoryUsed") / 1024 / 1024)
			debugMode.textureMemText.text = "Textures: "..debugMode.texMem.."Mb"
			debugMode.timeText.text = "Time: "..Round(system.getTimer() * 0.001).."s"
			if debugMode.frames < debugMode.fpsMin then
				debugMode.fpsMin = debugMode.frames
				debugMode.fpsMinText.text = "Min: "..debugMode.fpsMin
				debugMode.fpsMinTimeText.text = Round(system.getTimer() * 0.001).."s"
			end
			if debugMode.collisions > debugMode.collisionsMax then
				debugMode.collisionsMax = debugMode.collisions
				debugMode.setText(debugMode.collisionsMax, debugMode.collisionsMaxText, debugMode.collisionsMaxTimeText)
			end
			if debugMode.images > debugMode.imagesMax then
				debugMode.imagesMax = debugMode.images
				debugMode.setText(debugMode.imagesMax, debugMode.imagesMaxText, debugMode.imagesMaxTimeText)
			end
			if debugMode.sprites > debugMode.spritesMax then
				debugMode.spritesMax = debugMode.sprites
				debugMode.setText(debugMode.spritesMax, debugMode.spritesMaxText, debugMode.spritesMaxTimeText)
			end	
			if #transition._transitionTable > debugMode.transitionsMax then
				debugMode.transitionsMax = #transition._transitionTable
				debugMode.setText(debugMode.transitionsMax, debugMode.transitionsMaxText, debugMode.transitionsMaxTimeText)
			end
			debugMode.frames = 0
			debugMode.collisions = 0
			debugMode.images = 0
			debugMode.sprites = 0
			-- print(system.getInfo("androidAppVersionCode"))
			debugMode.Timer()
		end
	)
end

function debugMode.resetStats()
	debugMode.fpsMin = 30
	debugMode.collisionsMax = 0
	debugMode.imagesMax = 0
	debugMode.spritesMax = 0
	debugMode.transitionsMax = 0
end

if debugMode.debugLevel == nil then
		debugMode.debugLevel = 0
		listener.Add("Error Handler", "unhandledError", debugMode.errorListener)
	elseif debugMode.debugLevel > 0 then
		debugMode.frames = 0
		debugMode.collisions = 0
		debugMode.images = 0
		debugMode.sprites = 0
		debugMode.texMem = 0
		debugMode.resetStats()
		if debugMode.fpsText == nil then
			debugMode.timeText = Text(grpInterface, "Time: 0s", 340, 25, native.systemFont, 24)
			debugMode.fpsText = Text(grpInterface, "FPS: 0", 75, 50, native.systemFont, 24)
			debugMode.collisionsText = Text(grpInterface, "Collisions / s: 0", 75, 75, native.systemFont, 24)
			debugMode.imagesText = Text(grpInterface, "Images / s: 0", 75, 100, native.systemFont, 24)
			debugMode.spritesText = Text(grpInterface, "Sprites / s: 0", 75, 125, native.systemFont, 24)
			debugMode.transitionsText = Text(grpInterface, "Transitions / s: 0", 75, 150, native.systemFont, 24)
			debugMode.memoryText = Text(grpInterface, "Memory: "..Round(collectgarbage("count")).."Kb", 100, 175, native.systemFont, 24)
			debugMode.textureMemText = Text(grpInterface, "Textures: 0Mb", 300, 175, native.systemFont, 24)
			debugMode.fpsMinText = Text(grpInterface, "Min: 30", 250, 50, native.systemFont, 24)
			debugMode.collisionsMaxText = Text(grpInterface, "Max: 0", 250, 75, native.systemFont, 24)
			debugMode.imagesMaxText = Text(grpInterface, "Max: 0", 250, 100, native.systemFont, 24)
			debugMode.spritesMaxText = Text(grpInterface, "Max: 0", 250, 125, native.systemFont, 24)
			debugMode.transitionsMaxText = Text(grpInterface, "Max: 0", 250, 150, native.systemFont, 24)
			debugMode.fpsMinTimeText = Text(grpInterface, "0s", 375, 50, native.systemFont, 24)
			debugMode.collisionsMaxTimeText = Text(grpInterface, "0s", 375, 75, native.systemFont, 24)
			debugMode.imagesMaxTimeText = Text(grpInterface, "0s", 375, 100, native.systemFont, 24)
			debugMode.spritesMaxTimeText = Text(grpInterface, "0s", 375, 125, native.systemFont, 24)
			debugMode.transitionsMaxTimeText = Text(grpInterface, "0s", 375, 150, native.systemFont, 24)
			debugMode.consoleText = Text(grpInterface, "", 175, 175, native.systemFont, 24)
			debugMode.consoleCount = 1
			debugMode.Timer()
			Runtime:addEventListener("enterFrame", debugMode.countFPS)	
		end
		timer.performWithDelay(5000,
			function()
				debugMode.resetStats()
			end
		)
	end

function menu.optionsTap(event)
	local X, Y = inputToStage(event.x, event.y)
	if getDistance(X, Y, 540, 350) < 1000 then
		debugMode.toggleCount = debugMode.toggleCount + 1
		if debugMode.toggleCount == 10 then
			debugMode.toggleCount = 0
			if debugMode.debugLevel ~= 1 then
				debugMode.debugLevel = 1
				displayFloatyText(540, 1600, "Debug Enabled", 2500)
			else
				debugMode.debugLevel = 0
				displayFloatyText(540, 1600, "Debug Disabled", 2500)
			end
		end
	end
end

if debugMode.debugLevel ~= 0 then
    debugMode.console("Spawn blocked..")
end

Apologies for the imperfect formatting, I was struggling to get it to indent properly here.
I suspect this isn’t the most elegant code example, but it seems to have got the job done, and I think it’s quite simple to read / understand, so thought I’d share so others could at least benefit from my headaches over the past month!!

@troylyndon - thanks very much.
I’m not far off asking for this and will certainly keep it in mind, and really appreciate the offer.
Here’s an example of what I’ve been banging on about:

That’s a dramatic improvement! Congratulations on that. One question though, what are you using transitions for? 1000 transitions per second seems too much to me. Let’s say this constantly works for 3 seconds without removing single one of them, then you have 3000 transitions. That seems too much to me. I’m pretty sure you can do some tricks to reduce this dramatically.

Thank you!
I actually feel quite chuffed with the changes I’ve implemented recently with the suggestions made on this very thread.
I think the transitions stat is slightly different from the rest, as it uses #transition._transitionTable - so it’s giving a running count of currently existing transitions rather than those created each second?
In answer to your question I use transitions for loads of things - it’s easily one of my favourite things in the SDK.
I use them to move objects, resize them, fade them, rotate them, etc.
This being said I’ve no idea why it’s still hovering between 200 and 600 in “normal” operation - and seems kinda high to me too and a direct correlation to the low FPS…! :man_shrugging:

I don’t know how much would it affect but instead of using transitions to move or rotate objects with transition, you can easily pack them into a single Runtime(“enterFrame”) listener. Like if you’re using it to move your enemies, instead of calling transition for every single enemy, you could easily pack those objects into a table and move them in a single Runtime listener. That’s how I handle it in my own projects.

1 Like

Hiya, I’m not 100% sure what you mean here. All enemies are already in a table, I use a sprite listener to check the end of the animation sequence which then checks if the enemy needs to move, turn or attack. Is this being slow because there’s a sprite listener on every enemy? If I used an enterFrame - would I not still check every enemy and move them with a transition? Or are you saying it’s best to just set their x and y instead?

I’m actually curious about what you use transitions for. If you are using them to move your characters, a better choice would be to move them in a single enterFrame function by setting their x and y’s with their respective velocity values.

Like I said, I haven’t used that much transitions before so I can’t say I’m certain that’s the cause but looking at those values, hundreds of transitions in a single second is just too much. There’s definitely something wrong there.

Can you share a simple transition line you are using and say “this line is for X and created Y many times”?

1 Like

@bgmadclown - I would never recommend using “enterframe” for anything, because the code will end up running at whatever your fps (frames per second) is set to. Just my two cents.

1 Like

@troylyndon depending on the situation, enterFrame listeners can be the best and sometimes even the only way to address the issue.

For instance, if you need to update something every frame, how would you do it? If a score or a clock needs to be updated every frame, then what could be easier and more fitting than using an enterFrame listener? Also, using transitions and timers, as well as other things, create enterFrame listeners of their own.


enterFrame listeners are great and they can make life a lot easier. It’s just a matter of knowing when and how to use them correctly.

2 Likes

@troylyndon that could be easily solved by delta timing or that’s what I prefer.

I’m definitely not against transitions or anything but using them for basics like movement etc. can cause more problems than it solves. I mostly prefer them with animations where it doesn’t need to run hand in hand with the game itself.

1 Like

The enterframe used by transitions is written in C, and as part of the engine, is much faster than you might realize. My first mobile app used a traditional 30 FPS game loop and I’ve not done so since, because it’s simply not necessary for most things in a game.

For example, Score can be updated 10 times a second rather than 30 or 60 times per second.

Every bit of CPU savings is especially important for some Android devices which are notoriously slow to begin with.

1 Like

I am not against using transitions for simple things. I’m just saying it’s bad practice to use it for every single thing. You can definitely assign score updating to transitions for convenience but like @XeduR said, they all have their own enterFrame listeners meaning you don’t avoid using enterFrame at all. If you use too much of it like 200-600 a second, there is a chance that you are creating bottlenecks.

(@DigiNick I see you are following the topic. Can you please post your most used transition call and say “this transition is for X and created Y many times”? We could easily make progress if you could share that.)

1 Like

@troylyndon You are mistaken about that. Please take a look at the actual code for the transition framework over at GitHub. The entire framework is written in plain old Lua. There are no C bindings or anything.

1 Like