-
-
Notifications
You must be signed in to change notification settings - Fork 266
Description
- axmol version: 3.0.0-597022e
- devices test on: iPhone 14 Pro, MacBook Pro (Apple M1 Max), Pixel 6a
- developing environments
- NDK version: r27d
- Xcode version: 26.2
- cmake version: 4.2.1
Since commit 127ddac, Color32 has replaced Color3B, and a node’s opacity has become part of its color state. While this refactor is understandable, it has introduced multiple incorrect behaviors related to cascade opacity.
Issue 1
Cascade Color: OFF & Cascade Opacity: ON
=> Opacity is not propagated to children when modified via setColor instead of setOpacity.
Reproduction
node->setCascadeColorEnabled(false);
node->setCascadeOpacityEnabled(true);
auto color = node->getColor();
color.a = 127; // change opacity via color
node->setColor(color);Result
The node’s opacity changes, but its children are unaffected.
Cause
Calling setColor triggers:
updateCascadeColorupdateDisplayedColor
However:
setOpacityis not calledupdateDisplayedColoronly propagates to children when_cascadeColorEnabled==true
As a result, opacity propagation is skipped unless cascade color is enabled
Proposed Fix
Handle opacity cascading inside updateDisplayedColor when _cascadeOpacityEnabled is true:
void Node::updateDisplayedColor(const Color32& parentColor)
{
...
if (_cascadeColorEnabled)
{
for (const auto& child : _children)
{
child->updateDisplayedColor(_displayedColor);
}
}
else if (_cascadeOpacityEnabled)
{
for (const auto& child : _children)
{
child->updateDisplayedOpacity(_displayedColor.a);
}
}
}Issue 2
Cascade Opacity: OFF
=> A parent’s opacity change has no effect on the node itself, even when the parent has cascade color and/or cascade opacity enabled.
Reproduction
node->setCascadeOpacityEnabled(false);
node->parent->setOpacity(127); // parent changes opacityResult
The parent’s opacity changes, but the node (its child) is unaffected.
Cause
In updateDisplayedColor, _cascadeOpacityEnabled is incorrectly used to gate whether the node applies its parent’s alpha:
if (_cascadeOpacityEnabled)
_displayedColor.a = _realColor.a * parentColor.a / 255.0f;This causes opacity inheritance from the parent to be disabled entirely when _cascadeOpacityEnabled is false.
Proposed Fix
Always apply parent opacity when computing _displayedColor, and remove the conditional:
void Node::updateDisplayedColor(const Color32& parentColor)
{
_displayedColor.r = _realColor.r * parentColor.r / 255.0f;
_displayedColor.g = _realColor.g * parentColor.g / 255.0f;
_displayedColor.b = _realColor.b * parentColor.b / 255.0f;
_displayedColor.a = _realColor.a * parentColor.a / 255.0f;
updateColor();
...
}Suggested Final Implementation
void Node::updateDisplayedColor(const Color32& parentColor)
{
_displayedColor.r = _realColor.r * parentColor.r / 255.0f;
_displayedColor.g = _realColor.g * parentColor.g / 255.0f;
_displayedColor.b = _realColor.b * parentColor.b / 255.0f;
_displayedColor.a = _realColor.a * parentColor.a / 255.0f;
updateColor();
if (_cascadeColorEnabled)
{
for (const auto& child : _children)
{
child->updateDisplayedColor(_displayedColor);
}
}
else if (_cascadeOpacityEnabled)
{
for (const auto& child : _children)
{
child->updateDisplayedOpacity(_displayedColor.a);
}
}
}Additional Recommendation
I suggest changing the default value of _cascadeOpacityEnabled to true.
In many common game scenarios, developers frequently adjust the opacity of an entire node hierarchy in one operation, for example:
- Fading in/out a popup together with its labels, sprites, and UI elements
- Fading in/out a character’s root node when using skeletal animations (e.g. spawn / death transitions)
Defaulting cascade opacity to true better matches typical usage patterns and reduces the likelihood of subtle visual bugs.