Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Quick question about the performance of containers
Started by Quitalizner Dec 10 2018 07:49 PM

19 replies to this topic
containers lots of containers

Best Answer roaminggamer , 11 December 2018 - 09:24 AM

Yes, it can cause problems.  Excessive use of containers can cause performance issues. 

 

As Dave pointed out, each container involves a masking operation.  Aside from being expensive to do a bunch of unnecessary masking operations, if you start the put containers in containers you'll soon hit the masking depth limit.

 

You can easily give a group a known dimension:

 

1. Create a 16x16 transparent PNG and add it to your project folder of in a subfolder. (I call mine fillT.png)

2. For a 400 x 400 'group' do this:

local group = display.newGroup()
local fill = display.newImageRect( group, "fillT.png", 400, 400 ) 

Now, as long as you do not place objects in the group where those objects' bounds fall outside the bounds of 'fill' you are good to go.

[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

Quitalizner

[GLOBAL: userInfoPane.html]
Quitalizner
  • Enthusiast

  • 38 posts
  • Corona SDK

I have been using containers to make presets of obstacles, so one container has one obstacle or set of interlinked obstacles. And I slap them together in random sequence one on top of the other. Some containers may have enterFrame listeners and non-physical collision listeners( uses contentBounds as shown in tutorials).

Is this performance intensive. Or a bad practice. 

 

P.S : I am not nesting containers though. But all belong to the same parent group.



[TOPIC: post.html]
#2

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

@Quitalizner,

 

1. When you say container, do you mean the object produced by this function display.newContainer()  or do you mean display groups and containers?

 

2. What do you mean when you say 'interlinked'?  Do you mean you've added a physics body to the group/container?

 

Can you show some code demonstrating what you mean?

 

(Please remember to format code posts for legibility with the <> button above).

 

 

PS - I wouldn't worry too much about optimization early on.  If you're just learning this stuff it is better to take a more ad hoc approach initially.  Then, as you proceed you will find which solutions are superior and which are worse.


Edited by roaminggamer, 10 December 2018 - 09:28 PM.


[TOPIC: post.html]
#3

Quitalizner

[GLOBAL: userInfoPane.html]
Quitalizner
  • Enthusiast

  • 38 posts
  • Corona SDK

Yes, it's the display.newContainer.

 

To explain the scenario of what i meant by interlinked.

If you have played the game mmm fingers. You'd have a more clear picture of what i'm about to say.

For example:- If have a simple a rotating obstacle. Its defined in a container and i set a unique name to that container.

Now if I want a more advanced form of that rotating obstacle. I create another container and add few more obstacles to it and check if it has a feasible path for player to pass through, again I set a unique name to that container. 

Now that I have two different containers which are preset. I call them randomly and stack them on top of each other.

 

I know interlinked is not the right word, just that i want to make sure there is a feasible path for the player to pass through, which would be difficult to create if i just randomize all the obstacles.

 

So below is a module for creating moving obstacles.

I have just presented a simple obstacle here. Its a grip which has a enterFrame event added to make it move in a certain manner.

Some might have collision listeners as well( the non-physical kind https://docs.coronalabs.com/tutorial/games/nonPhysicalCollision/index.html

 

Since I am creating many containers. Can it run smoothly, I see that its running fine on the simulator. But can a mobile handle it.

I call atmost  60 containers.

local function createContainer(currentHeight)
	local container = display.newContainer(measure.cliffWidth, 0)
	container.x = measure.cliffStart
	container.y = currentHeight
	container.anchorX = 0
	container.anchorY = 0
	container.anchorChildren = false
	return container
end

function _M.movingSingleGrip(currentHeight)

	local container = createContainer(currentHeight)
	local grip = display.newCircle(container,measure.cliff4,60,30)
	grip.type = "grip"
	grip.speed = 1
	grip.isMoving = true
	local height = 120 								-- takes one container space
	container.height = container.height + height
	container.numElements = 1
	container.row = 1
	container.name = "msg"

	function container:eachFrame()
		local circle = container[1]
		if circle.x < measure.cliff2 then
			circle.speed = 1
		elseif circle.x > measure.cliff6 then
			circle.speed = -1
		end
		circle.x = circle.x + circle.speed
	end
	eachFrame.add(container)

	return container

end


[TOPIC: post.html]
#4

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,318 posts
  • Enterprise

unless you actually need the masking (and it's not apparent that you do) then just use plain old groups -- any question about container performance then becomes moot.



[TOPIC: post.html]
#5

Quitalizner

[GLOBAL: userInfoPane.html]
Quitalizner
  • Enthusiast

  • 38 posts
  • Corona SDK

I don't need the masking, but it seems easy to position elements in a container and make presets of them. And since we cant( not aware if its possible) explicitly set the height and width of the group. I thought I'd go with containers, it seems to be working fine. But I just wanna be sure whether it may cause any problems down the road.



[TOPIC: post.html]
#6

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

  Best Answer

Yes, it can cause problems.  Excessive use of containers can cause performance issues. 

 

As Dave pointed out, each container involves a masking operation.  Aside from being expensive to do a bunch of unnecessary masking operations, if you start the put containers in containers you'll soon hit the masking depth limit.

 

You can easily give a group a known dimension:

 

1. Create a 16x16 transparent PNG and add it to your project folder of in a subfolder. (I call mine fillT.png)

2. For a 400 x 400 'group' do this:

local group = display.newGroup()
local fill = display.newImageRect( group, "fillT.png", 400, 400 ) 

Now, as long as you do not place objects in the group where those objects' bounds fall outside the bounds of 'fill' you are good to go.


  • Quitalizner likes this

[TOPIC: post.html]
#7

Quitalizner

[GLOBAL: userInfoPane.html]
Quitalizner
  • Enthusiast

  • 38 posts
  • Corona SDK

Oh I see, thanks for the great advice roaminggamer. One last question, can I position the elements in the group relative to it similar to the way we position elements in the container. 

 

For example:-

local contain = display.newContainer(200, 200)
local object = display.newRect(contain, 0,0, 40,40) -- This will be positioned at the center of the container.

 -- Whereas

local group = display.newGroup()
local fill = display.newImageRect(group, "fillT.png", 200,200)
local object = display.newRect(group, 0,0, 40,40)  -- This will be positioned at the origin of the screen, instead of the group.

Should I use something like contentBounds to make position it inside the group.


[TOPIC: post.html]
#8

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

I'm not sure what the confusion is, but these are essentially the same (minus masking)

local contain = display.newContainer(200, 200)
local object = display.newRect(contain, 0,0, 40,40) 
contain.x = display.contentCenterX
contain.y = display.contentCenterY

-- Object is at <0,0> in the container.
-- The center <0,0> of the container is in the center of the screen
-- Thus, the center of the rect is also in the center of the screen
local group = display.newGroup()
local object = display.newRect(group, 0,0, 40,40)
group.x = display.contentCenterX
group.y = display.contentCenterY

-- Object is at <0,0> in the group.
-- The center <0,0> of the group is in the center of the screen
-- Thus, the center of the rect is also in the center of the screen

Tip: I said something above that isn't entirely true.  Groups do not have a center.  That said, <0,0> can be treated like the center, then a group behaves just like a container (excluding masking).



[TOPIC: post.html]
#9

Quitalizner

[GLOBAL: userInfoPane.html]
Quitalizner
  • Enthusiast

  • 38 posts
  • Corona SDK

Oh, alright then. I'll give it a try and see if i have any doubts. Thanks a lot roaming gamer for your advice on transparent filling.



[TOPIC: post.html]
#10

nick_sherman

[GLOBAL: userInfoPane.html]
nick_sherman
  • Corona Geek

  • 1,749 posts
  • Corona SDK

Containers are a relatively new addition to Corona, compared to the age of the SDK. Therefore I never bothered switching to them, and used a method similar to RG.

 

If a display group will have known bounds, say a sidebar or a popup window, I create a newRect of that size and add it to the group, and store it as a parameter 'box' on the group. I then know to place an object at the top left of the group, I give it a topLeft anchor point and place it at -group.box.width/2, -group.box.height/2.

 

This also allows me to size objects dynamically depending on the size of the group. If I want a panel in the group that fills the left half, I make the size group.box.width/2, group.box.height. If I then decide the group needs to be bigger, I don't need to change the size and position of all the components within it.

 

As RG says in order for this to work you have to ensure no objects go outside of the bounds or the positioning of objects after that may be off.


  • roaminggamer likes this

[TOPIC: post.html]
#11

Quitalizner

[GLOBAL: userInfoPane.html]
Quitalizner
  • Enthusiast

  • 38 posts
  • Corona SDK

I tried it out, now I understand how I can go about replacing containers with groups.

I only used containers because i read the containers width and height have to be defined and it isn't dynamic. So it felt easier to handle and also we can set anchors to the container which is what i needed. 

Now I see that we can do the same with groups, since we can't set anchor property to the group, we can set it to box object that we use for sizing. 

But one thing I'm not sure yet is whether using any transition or enterFrame events and moving an object outside the width of the box, might increase the bounds of the box.

Thanks for the advice nick. 

Beginners like me really appreciate certain tips and tricks that experienced guys like you all use.



[TOPIC: post.html]
#12

nick_sherman

[GLOBAL: userInfoPane.html]
nick_sherman
  • Corona Geek

  • 1,749 posts
  • Corona SDK

 

But one thing I'm not sure yet is whether using any transition or enterFrame events and moving an object outside the width of the box, might increase the bounds of the box.

 

 

Well, I must add I've only ever used this for static UI elements, or when objects within the group don't move even if the group itself does.

 

If objects must move outside of the 'box' then they don't really belong in the box. For something like a drag-drop mechanism, when something is picked up and being dragged I will remove it from the 'container-style' group and place it in the scene group. Then when it's dropped, re-insert and re-position into the appropriate group based on where it was dropped.



[TOPIC: post.html]
#13

Quitalizner

[GLOBAL: userInfoPane.html]
Quitalizner
  • Enthusiast

  • 38 posts
  • Corona SDK

I have another doubt, @roaminggamer. Will using groups with transparent fills cause performance issues. Since transparency might require some additional rendering( correct me if i'm wrong ). I would be using a lot of groups with that transparent fill object method.

 

How does corona engine go about rendering transparent images.



[TOPIC: post.html]
#14

nick_sherman

[GLOBAL: userInfoPane.html]
nick_sherman
  • Corona Geek

  • 1,749 posts
  • Corona SDK

I haven't come across any problems and I have a LOT of display objects, transparent and opaque on screen at once. I wouldn't worry about a potential problem unless you actually come across it. Drawing a lot of objects might take some time and then I would stagger them to prevent locking up the main thread, but once drawn you should be ok.

 

If you're comparing it to something like Unity where you're constantly worrying about draw calls and batching textures, with different shaders for transparent and opaque objects, this is an area where I think Corona has the upper hand. It's very difficult to reach a performance limit with just on-screen objects. If you have a scrolling game with lots of stuff potentially off-screen, then it would be time to write a culling routine that makes sure these objects aren't actually drawn until they can be 'seen'.



[TOPIC: post.html]
#15

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

Tip: You can avoid the fill object all together and set up a hybrid solution based on Nick's suggestion and a bit of other goodness like this:


local function containerBuilder( x, y, w, h )
   local group = display.newGroup()
   --
   group.x = x
   group.y = y
   --
   group.box = {
      width = w,
      height = h,
      left = function() return group.x - w/2 end,
      right = function() return group.x + w/2 end,
      top = function() return group.y - h/2 end,
      bottom = function() return group.y + h/2 end,
   }
   --
   return group
end

-- Later, let's make a 200 x 300 group like this.
--

local group = containerBuilder( display.contentCenterX, display.contentCenterY, 200, 300 )

print( group.x, group.y, group.box.width, group.box.height )
print( group.box.left(), group.box.right(), group.box.top(), group.box.bottom() )
group.x = group.x - 100
group.y = group.y + 100

print( group.x, group.y, group.box.width, group.box.height )
print( group.box.left(), group.box.right(), group.box.top(), group.box.bottom() )

Reminder: All of this falls apart if you put objects in the group and those objects' bounds are outside the 'assumed' bounds of the group.


Edited by roaminggamer, 12 December 2018 - 12:45 PM.


[TOPIC: post.html]
#16

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

You could even do this:
function display.myNewGroup( x, y, w, h )
   local group = display.newGroup()
   --
   group.x = x
   group.y = y
   group.w = w
   group.h = h
   function group.left() return group.x - w/2 end
   function group.right() return group.x + w/2 end
   function group.top() return group.y - h/2 end
   function group.bottom() return group.y + h/2 end
   --
   return group
end

-- Later, let's make a 200 x 300 group like this.
--

local group = display.myNewGroup( display.contentCenterX, display.contentCenterY, 200, 300 )

print( group.x, group.y, group.w, group.h)
print( group.left(), group.right(), group.top(), group.bottom() )
group.x = group.x - 100
group.y = group.y + 100

print( group.x, group.y, group.w, group.h)
print( group.left(), group.right(), group.top(), group.bottom() )

 

Edited by roaminggamer, 12 December 2018 - 12:46 PM.


[TOPIC: post.html]
#17

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,318 posts
  • Enterprise

Will using groups with transparent fills cause performance issues. Since transparency might require some additional rendering( correct me if i'm wrong )

 

 

all of that is correct - a visible rect with a texture that just happens to be transparent will still be fully rendered (and will require an alpha blend per pixel) chewing up the gpu's overall fill rate.  just use a simple display.newRect() and set .isVisible=false, then won't be rendered at all, but will still affect the bounds of the group it's within... if you need it to...

 

or,... reconsider why you even care what the group's bounds are.  are you hit-testing against the group bounds itself rather than its contents?  (if so, what happens when the group is sparsely populated?)  because if you hit-test against the contents then who cares what size the group's bounds are?


  • roaminggamer likes this

[TOPIC: post.html]
#18

Quitalizner

[GLOBAL: userInfoPane.html]
Quitalizner
  • Enthusiast

  • 38 posts
  • Corona SDK

@nicksherman , I do have a lot of objects off-screen and they move in a top-down scroller way towards the player. All the objects in their respective container are randomly generated before the player has access to it. I really need to write a culling function, but I'm not aware how I need to approach it. Can you please provide a gist of it. 

 

@roaminggamer, Thanks for the advice on creating groups without fillObject. I'll check if I would run into any problems with it. I have to see how it will handle dynamic change of height of group as I add more obstacles to it.

 

@davebollinger, Thanks for clarifying me on transparency. I googled and could only find articles in unity. I thought since this is a 2D engine the transparent images don't require rendering. Since you asked if I am hit-testing against the group bounds. I do hit-testing for certain containers, so that they activate when player is within the bounds of that container. I am not hit-testing all the groups for the player. Only for containers with a certain obstacle.

 

I'm looking forward for any advice on culling as nick suggested. Will,  If all the objects are drawn and set to isVisible = false while offScreen and switching them to isVisible = true when closer to screen bounds work?



[TOPIC: post.html]
#19

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,318 posts
  • Enterprise

you're talking "low-level culling" - taking an already-defined "thing" and decide whether to actually render it.  in corona terms, it would be like having an existing rectangle, then based on checking its bounds vs screen set .isVisible accordingly per frame.  corona already does this internally, with native code, and you're unlikely to beat it with interpreted lua.

 

I think Nick was talking "high-level culling":  simply defer creating all those offscreen objects until you actually need them ((fe within some threshold distance of the visible screen) then remove them once beyond the screen in the other direction.  anything that's been "high-level culled" wouldn't even exist in the display, so doesn't even factor into "low-level culling".

 

that's how you (potentially) beat lower-level native code with higher-level interpreted code (otherwise don't bother, you could even make it worse rather than better!)



[TOPIC: post.html]
#20

Quitalizner

[GLOBAL: userInfoPane.html]
Quitalizner
  • Enthusiast

  • 38 posts
  • Corona SDK

Ah, I see now. Maybe I'll populate all the coordinates and properties of respective objects into a table and make a call to draw them. It would get complex very fast. But I'll make an attempt and see how it goes. Thank you davebollinger 




[topic_controls]
[/topic_controls]

Also tagged with one or more of these keywords: containers, lots of containers