Some time and commits ago (assume like around 50-60 compared to yesterday) I updated the castle code locally and I was working on my game flawlessly. When I pushed the changes to master yesterday, the build started on github (it should be using the latest CGE) and in result I got a build which was failing on lines like this:
LCell := ACastleTransformDesignField.Items[0] as TCastleImageTransform;
and design file of that CastleTransformDesign was containing just basic hierarchy:
the error is basically EInvalidCast.
After some research I updated the code of CGE to latest locally, and I found out that all TCastleScene components (on based on that, like TCastleText, TCastleImageTransform, which I use) started to require additional block Items[0] to get to exact component that I need (usually I load dynamically designs and wire its subcomponents), thus Design contains the image not directly but first some intermediate Transform and that Transform then holds Image.
So I think this is some change in CastleScene which got restructured and broke this flow.
So regardless of intentions , decisions and so on, I’m here just to report and ask if it stays like this in future or it is really an issue to be fixed.
Disclaimer. I know this is actually my fault as I shouldn’t be using explicit indexing Items and nested Items, but rather names of components, which should be error-prone to such things. Ofc I will try to rework it in future, but also I’ve adjusted code to new “paradigm” and took those risks for now, it is not a big deal
Thanks for bringing this to my attention – I indeed did a change that is likely responsible for what you observe. Though I didn’t actually realize that I broke compatibility for usage like you show.
Short version of the answer: The change will stay (we need this to fix another problem), but I added in a commit I did just now a feature that will make your life easier, the access will be easier and be invulnerable to such changes in the future: TCastleTransformDesign.DesignRoot read-only property. So instead of your own old
// don't use this anymore
LCell := ACastleTransformDesignField.Items[0] as TCastleImageTransform;
→ you want to do this (if I understand the situation from the description correctly):
// use this now, and don't worry how deep is DesignRoot inside ACastleTransformDesignField :)
LCell := ACastleTransformDesignField.DesignRoot;
Longer explanation what happened:
Note: We didn’t make any change to TCastleScene (which doesn’t create any internal TCastleTransform children) or TCastleImageTransform (which was and is still creating one internal child, an instance of TCastleScene) lately.
Previously it added the loaded components as the direct child of TCastleTransformDesign – this was causing problems, because it meant that root (and only root) of loaded design has to
be SetTransient. This means that trying to detect ray hits to this root wasn’t working properly.
In new approach, the TCastleTransformDesign creates additional child, FDesignContainer, that is SetTransient. And only adds newly loaded hierarchy as a child of FDesignContainer.
So, this was a deliberate change, I think the new organization is better, the right component is marked “transient”. You should not assume whether the loaded contents are directly or indirectly children of TCastleTransformDesign.
Solutions:
As you say, you could use names. Like MyRoot := MyDesign.DesignedComponent('RootInDesign');
But we could also make it easier, and just expose a direct read-only way to get design root. Which I’ve done now → see top of this answer
Thanks, @michalis for sorting this out so quickly (and also the other issue I reported on github), I will try this new approach with DesignRoot field and write my findings.
Hi, I tried all this during weekend and it works pretty much good, so I changed it everywhere and got rid of crawling through the hierarchy, which is nicer. so I’m happy with this, thank you, @michalis !