0

I am creating a 3-D game with a cave as the main environment. The cave is made of a large number of ring segments, one attached to the other, thus creating a currently small tunnel system.

If the Player is inside the cave, only a small part of the segments are visible. I am figuring that actually hiding the not-visible segments could save a lot of gpu time, which I need for other objects like buildings or enemies.

So what I try to do first is hiding the entire cave and then unhiding the visible segments by turning ‚node.isHidden’ true and false. The particular nodes are being found and accessed by their names: ‚Node.childnode (withName: „XYZ003“, recursively: false).isHidden = true‘ (or false).

It works to the point where the segments are unhidden, but once I am trying to hide a previously unhidden segment, the renderer crashes with an EXC_BAD_ACCESS.

Doing the hiding on a hidden object (of course useless, but helping to understand the problem) is fine, so is unhiding unhidden segments.

Following the hint of another thread, I moved the routine into the renderer delegate so not doing the switching during the wrong time, but instead during the phase in which such changes are supposed to happen, but this did not help. As an alternative, I did the hiding (and unhiding) by SCNActions, but I received the same result, which really puzzles me, as this would be kind of the ‚official way‘ to do it...

I also played around with the ‚recursively’ boolean, getting the same outcome (works for unhide, crashes on isHidden = true).

Then I tried to change opacity or other properties of the nodes - which worked perfectly. On the other hand, trying to remove the nodes from the parent resulted in the mentioned crash as well.

I need this to work, because older hardware could never cope with several thousand nodes (trying this, the frame rate dropped to 10fps, even without enemies around). And newer hardware might break down once the enemies appear...

My thinking is that the pointer is somehow messed up by the first unhiding (and hence the BAD_ACCESS error), so maybe an additional bonding (often seen with spritekit-routines) or another way to get the node-pointer could be the solution. On the other hand, if the pointer is broken, why can I still access all other properties? Maybe it‘s the subnodes that cause the problem - everyone of the nodes has 20 subnodes, which are supposed to change visibility, too.

Did anyone come across this behavior before me? I could not find anything during my google-research...

ULI
  • 41
  • 7

1 Answers1

1

Hiding and unhiding nodes frequently is typically not a problem by itself. You can hide a main node and any sub-nodes of the main node will automatically hide themselves, so you shouldn't have to loop them individually.

I'm not an expert debugger and don't know your skill level, but BAD_ACCESS can mean that you tried to send a msg to a block of memory that can't execute the message or whenever the app tried to deference a corrupt pointer. Search "What Is EXC_BAD_ACCESS and How to Debug It" for a decent tutorial on some options for dealing with it.

I do my changes in the render delegate as well, but depending on the number of changes and how long they take, I sometimes use timers to control the amount of changes that can be made in a certain amount of time. That way, and after some adjustments, I'm pretty sure that I'm not bogging it down to a point where it just spirals out of control.

Structure can matter - personal preference, but I try to setup an array of classes that create individual nodes (and sub-nodes) and therefore have direct access to them. That way I'm not iterating through the whole node structure or finding nodes by name. Sometimes a lot is going on before I really have to make a modification to the node itself and so I can loop through my array of classes, check values, compare, etc. before taking action that involves the display. That also gives me a chance to remove particle systems, remove actions, set geometry = nil and update logic counters when I need to remove a node.

I'm sure opinions vary, but this has worked well for me. Once I standardized the structure, I just keep repeating the pattern.

Hope that helps

Voltan
  • 1,170
  • 1
  • 7
  • 16
  • Thanks for your quick answer. The ring segments I was describing are actually made of 1 parent and an additional 20 subnodes, which, just as you mention, should turn off and on when the parent is switched. Concerning the duration of the changes - I tried to do the switchoff at the very beginning of the renderer delegate phase and nothing else to follow, so the timing shouldn‘t be the problem. But again, the app crashed. – ULI Feb 19 '20 at 19:47
  • Also, I tried the reference that you cited incidentally already yesterday, and I came across some weird behaviors - seems I have to do a lot more debugging than I thought - but I couldn‘t find the solution. Only I understood about the pointer or memory block which could be corrupt. But how should that be? The ring displays and after a few seconds is hidden again, with nothing happening in between - no other changes of the nodes... – ULI Feb 19 '20 at 20:24
  • Yeah, kind of hard to say without seeing the code. You might try looking at leaks, just to see if something big sticks out. If not, try to move the node - let it settle for a few seconds, then just move it one time - don't hide it, let it run for a bit. If moving still crashes, add a different node and get ride of cave stuff - just an invisible one with no structure to ensure it's not something in your sub-nodes or graphic content. Yeah, reaching here but sometimes just go the the simplest mode and build back up. – Voltan Feb 20 '20 at 03:27
  • I think I will try your suggestion. But even more, I am interested in the idea of fixing my cave to a specific array instead of searching by the name. I never liked the idea very much to do this in such a relative way. Should save some processing time as well - not having to create the name string to look for and avoiding the search...on the other hand, it will be a huge array... – ULI Feb 20 '20 at 05:12
  • So I stored the cave data inside an array, which is much nicer now. And it does actually work!!! But I think it is not because of the direct access of the nodes... Rather I found out that before, I was hiding the parent node before I added additional child nodes (lots of them). And then, turning them off and on probably was too much for the engine... When I took the array as a storage, I changed the position of the parent-hiding to the end of the child group. – ULI Feb 20 '20 at 17:19
  • Great - congrats on moving forward. Yeah, searching by name - I can't imaging that's very efficient for the engine. I wouldn't have thought that working with a hidden node would cause that kind of issue. I've done things with sub-nodes of hidden nodes, but not at that volume. – Voltan Feb 21 '20 at 18:27