CanvasItem
2026/4/14大约 6 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — CanvasItem
CanvasItem
节点继承关系
继承链:Node → CanvasItem
定义
CanvasItem 是所有"能在屏幕上画东西"的节点的基类。它管理可见性(Visible)、绘制顺序(ZIndex)、材质和自定义绘制。你不会直接创建 CanvasItem,但它的属性在所有 2D 和 UI 节点中都能用。
一句话理解:CanvasItem 给节点加上"能被看见"的能力——控制显示/隐藏、谁在前谁在后、怎么画。
打个比方:Node 是一张空白档案卡,而 CanvasItem 是在档案卡上贴了一张透明的塑料板。这张塑料板本身是透明的(看不见),但你可以控制它的透明度、给它上色、决定它和别的卡片的叠放顺序。所有 2D 画面——精灵、标签、线条、粒子——都继承了这张"透明塑料板"的能力。
节点用途
- 控制节点的可见性和颜色叠加
- 管理绘制顺序(Z 轴排序,谁在前谁在后)
- 应用材质(着色器(Shader)特效等)
- 自定义绘制(通过重写
_Draw方法)
使用场景
典型场景
- 显示/隐藏元素:控制敌人出现、宝箱打开时的动画、对话框弹出等。调用
Visible = false就能瞬间让节点(及其所有子节点)消失。 - 颜色叠加效果:给角色受伤时闪红、死亡时变灰、拾取道具时发光等。通过修改
Modulate属性即可实现。 - 自定义绘制:在
_Draw方法中画圆、线、矩形等几何图形,适合画血条、瞄准线、范围指示器等 HUD 元素。
不适用场景
常用节点搭配
| 搭配节点 | 用途 | 必需? |
|---|---|---|
| Node2D | 作为 Node2D 的父类能力 | 是(通过继承) |
| ShaderMaterial | 给 2D 节点添加着色器特效 | 视需求 |
| CanvasLayer | 创建独立的绘制层(如 UI 层、背景层) | 视需求 |
生效必备素材/资源
CanvasItem 本身不需要外部资源。但如果要使用材质(Material 属性),则需要 ShaderMaterial 或其他材质资源。
节点属性与信号
可见性属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| Visible | bool | true | — | 是否可见。隐藏时子节点也一起隐藏 |
| ShowBehindParent | bool | false | — | 是否绘制在父节点后面 |
| TopLevel | bool | false | — | 是否忽略父节点的变换,直接在画布根上绘制 |
颜色与材质属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| Modulate | Color | (1, 1, 1, 1) | — | 颜色叠加(染色效果),影响自身和所有子节点 |
| SelfModulate | Color | (1, 1, 1, 1) | — | 自身颜色叠加,只影响自身,不影响子节点 |
| Material | Material | null | — | 材质资源,用于着色器等特效 |
| UseParentMaterial | bool | false | — | 是否使用父节点的材质 |
绘制顺序属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| ZIndex | int | 0 | — | 绘制顺序,值越大越靠前(显示在越上面) |
| ZAsRelativeToParent | bool | false | — | Z 值是否相对于父节点。开启后子节点的 Z 值会在父节点基础上累加 |
| LightMask | int | 1 | — | 光照遮罩,决定受哪些光源影响 |
| TextureFilter | TextureFilterEnum | Inherit | — | 纹理过滤模式 |
提示与裁切属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| ClipChildren | ClipChildrenMode | Off | — | 裁切子节点模式(Off/Clip/ClipAndDraw) |
| HintAlign | HintAlignEnum | TopLeft | — | 自定义绘制时的对齐提示 |
| HintBaseline | real | 0.0 | — | 文本基线偏移 |
继承自 Node 的属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| Name | String | — | Node | 节点名称 |
| ProcessMode | ProcessModeEnum | Inherit | Node | 处理模式 |
| Script | Script | null | Node | 附加脚本 |
信号
| 信号 | 触发时机 | 继承自 | 说明 |
|---|---|---|---|
Draw | 需要重新绘制时 | — | 请求重绘通知 |
VisibilityChanged | 可见性发生变化时 | — | Visible 属性被修改时触发 |
ItemRectChanged | 节点的矩形区域变化时 | — | 通常在自定义绘制后触发 |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
DrawCircle(Vector2 pos, float radius, Color color) | void | 画一个实心圆(在 _Draw 中调用) |
DrawLine(Vector2 from, Vector2 to, Color color, float width) | void | 画一条线 |
DrawRect(Rect2 rect, Color color, bool filled) | void | 画一个矩形 |
DrawString(Font font, Vector2 pos, string text, ...) | void | 画文字 |
DrawDashedLine(...) | void | 画虚线 |
DrawArc(...) | void | 画弧线 |
DrawPolygon(...) | void | 画多边形 |
DrawSetTransform(Vector2 pos, float rot, Vector2 scale) | void | 设置绘制变换(在 _Draw 中调整绘制位置和旋转) |
QueueRedraw() | void | 请求重新绘制(标记需要重绘,下一帧自动调用 _Draw) |
Hide() | void | 隐藏节点(等同于 Visible = false) |
Show() | void | 显示节点(等同于 Visible = true) |
GetGlobalMousePosition() | Vector2 | 获取鼠标在全局坐标中的位置 |
代码示例
可见性与颜色叠加
C
// 隐藏节点(子节点也一起隐藏)
GetNode<CanvasItem>("Sprite").Visible = false;
// 显示节点
GetNode<CanvasItem>("Sprite").Show();
// 给节点染成红色(所有子节点也变红)
GetNode<CanvasItem>("Sprite").Modulate = new Color(1, 0, 0, 1);
// 只给自身染色,不影响子节点
GetNode<CanvasItem>("Sprite").SelfModulate = new Color(0.5f, 0.5f, 1, 1);
// 让节点半透明
GetNode<CanvasItem>("Sprite").Modulate = new Color(1, 1, 1, 0.5f);
// 让节点完全变白(闪白效果)
GetNode<CanvasItem>("Sprite").Modulate = Colors.White;GDScript
# 隐藏节点(子节点也一起隐藏)
$Sprite.visible = false
# 显示节点
$Sprite.show()
# 给节点染成红色(所有子节点也变红)
$Sprite.modulate = Color(1, 0, 0, 1)
# 只给自身染色,不影响子节点
$Sprite.self_modulate = Color(0.5, 0.5, 1, 1)
# 让节点半透明
$Sprite.modulate = Color(1, 1, 1, 0.5)
# 让节点完全变白(闪白效果)
$Sprite.modulate = Color.WHITE自定义绘制
C
// 自定义绘制(必须在 _Draw 方法中)
public override void _Draw()
{
// 画一个红色的圆
DrawCircle(new Vector2(0, 0), 50, Colors.Red);
// 画一条白色的线
DrawLine(new Vector2(0, 0), new Vector2(100, 100), Colors.White, 2);
// 画一个蓝色的矩形(空心)
DrawRect(new Rect2(-50, -50, 100, 100), Colors.Blue, false);
// 画一个绿色的矩形(实心)
DrawRect(new Rect2(50, -25, 80, 50), Colors.Green, true);
}
// 触发重绘(比如血量变化时)
public void UpdateHealthBar()
{
QueueRedraw();
}GDScript
# 自定义绘制(必须在 _draw 方法中)
func _draw():
# 画一个红色的圆
draw_circle(Vector2(0, 0), 50, Color.RED)
# 画一条白色的线
draw_line(Vector2(0, 0), Vector2(100, 100), Color.WHITE, 2)
# 画一个蓝色的矩形(空心)
draw_rect(Rect2(-50, -50, 100, 100), Color.BLUE, false)
# 画一个绿色的矩形(实心)
draw_rect(Rect2(50, -25, 80, 50), Color.GREEN, true)
# 触发重绘(比如血量变化时)
func update_health_bar():
queue_redraw()Z 轴排序
C
// 让角色始终显示在敌人前面
var player = GetNode<CanvasItem>("Player");
var enemy = GetNode<CanvasItem>("Enemy");
player.ZIndex = 1; // 玩家在前
enemy.ZIndex = 0; // 敌人在后
// 让子节点的 Z 值相对于父节点累加
player.ZAsRelativeToParent = true;
// 这样玩家的子节点 ZIndex=1 时,实际 ZIndex=1+父节点ZIndexGDScript
# 让角色始终显示在敌人前面
var player = $Player as CanvasItem
var enemy = $Enemy as CanvasItem
player.z_index = 1 # 玩家在前
enemy.z_index = 0 # 敌人在后
# 让子节点的 Z 值相对于父节点累加
player.z_as_relative_to_parent = true
# 这样玩家的子节点 z_index=1 时,实际 z_index=1+父节点z_index