【Godot4.3】CanvasShape资源化改造

2024-09-06 14:28

本文主要是介绍【Godot4.3】CanvasShape资源化改造,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

通过把之前自定义的CanvasShape类变成资源类型,将可以同时用于CanvasItem绘图和创建扩展的Node2DPolygon2D节点等。

本篇就完成CanvasShape类的资源化改造,并记录改造过程和思路。

CanvasShape资源类型体系

在这里插入图片描述

  • CanvasShape仍然为图形基类,提供共有的属性和方法,只不过改为继承自Resource,成为自定义资源类型
  • CanvasXXX代表具体的图形类,扩展自CanvasShape,因为继承的好处,可以只关注自己的参数设计

CanvasShape(图形基类)

# =============================================
# 名称:CanvasShape
# 类型:Resource
# 描述:资源化后的CanvasItem绘图函数图形基类
# 作者:巽星石
# 创建时间:202472515:25:24
# 最后修改时间:20249522:26:00
# =============================================
@tool
@icon("res://lib/绘图相关/CanvasShape/icons/CanvasShape.png")
class_name CanvasShape extends Resource
# ============================== 属性 ==============================
@export_category("CanvasShape")
# -------------------- 路径点
# 点集合
@export var points:PackedVector2Array = []:set(val):points = valemit_changed() # 触发资源的changed信号
# 是否闭合轮廓线
@export var close_path:bool = false:set(val):close_path = valemit_changed() # 触发资源的changed信号
# 是否绘制局部坐标系原点         
@export var draw_position:bool = false:set(val):draw_position = valemit_changed() # 触发资源的changed信号
# -------------------- 边线样式
@export_group("border")
## 是否绘制轮廓
@export var draw_border:bool = true:set(val):draw_border = valemit_changed() # 触发资源的changed信号 
## 虚线间隔
@export_range(0.0,100.0,1.0,"suffix:px") var dash = 0.0:set(val):dash = valemit_changed() # 触发资源的changed信号
## 轮廓线宽度
@export_range(0,100,1,"suffix:px") var border_width:int = 1:set(val):border_width = valemit_changed() # 触发资源的changed信号
## 轮廓线颜色
@export var border_color:Color = Color.BLACK:set(val):border_color = valemit_changed() # 触发资源的changed信号# -------------------- 边线样式
@export_group("fill")
## 是否绘制填充         
@export var draw_fill:bool = true:set(val):draw_fill = valemit_changed() # 触发资源的changed信号
## 填充颜色
@export var fill_color:Color = Color.WHITE:set(val):fill_color = valemit_changed() # 触发资源的changed信号# -------------------- 偏移
## 相对于坐标原点的偏移位置
@export var offset:Vector2 = Vector2.ZERO:set(val):offset = valemit_changed() # 触发资源的changed信号    
# -------------------- 阴影设置
@export_group("shadow")
## 是否绘制阴影
@export var draw_shadow:bool = false:set(val):draw_shadow = valemit_changed() # 触发资源的changed信号
## 阴影颜色               
@export var shadow_color:Color = Color(Color.BLACK.lightened(0.1),0.6):set(val):shadow_color = valemit_changed() # 触发资源的changed信号
## 阴影偏移      
@export var shadow_offset:Vector2 = Vector2(10,10):set(val):shadow_offset = valemit_changed() # 触发资源的changed信号
# 顶点绘制参数
@export_group("point")
## 是否绘制顶点              
@export var draw_points:bool = false:set(val):draw_points = valemit_changed() # 触发资源的changed信号
## 顶点圆半径
@export var point_r = 3:set(val):point_r = valemit_changed() # 触发资源的changed信号
## 顶点轮廓线宽度
@export var point_border_width:int = 1:set(val):point_border_width = valemit_changed() # 触发资源的changed信号
## 顶点轮廓线颜色
@export var point_border_color:Color = Color.BLACK:set(val):point_border_color = valemit_changed() # 触发资源的changed信号
## 顶点填充颜色
@export var point_fill_color:Color = Color.WHITE:set(val):point_fill_color = valemit_changed() # 触发资源的changed信号     
# 矩形范围绘制参数
@export_group("rect2")
## 是否绘制矩形范围      
@export var draw_rect2:bool = false:set(val):draw_rect2 = valemit_changed() # 触发资源的changed信号
## 矩形轮廓线宽度
@export var rect2_border_width:int = 1:set(val):rect2_border_width = valemit_changed() # 触发资源的changed信号
## 矩形轮廓线颜色        
@export var rect2_border_color:Color = Color.AQUAMARINE:set(val):rect2_border_color = valemit_changed() # 触发资源的changed信号# ============================== 方法 ==============================
func draw(canvas:CanvasItem) -> void:# 对所有点进行位移变换var offset_points = Transform2D().translated(offset) * points# 1.绘制阴影if draw_shadow and offset_points.size()>2: # 至少有3个点var shadow_points = Transform2D().translated(shadow_offset) * offset_pointscanvas.draw_colored_polygon(shadow_points,shadow_color) # 2.绘制矩形范围if draw_rect2:canvas.draw_rect(get_rect(),Color(rect2_border_color,0.5),false,rect2_border_width)# 3.绘制填充if draw_fill and fill_color and offset_points.size()>2: # 至少有3个点canvas.draw_colored_polygon(offset_points,fill_color)# 4.绘制轮廓if draw_border and border_width!=0 and border_color!=null:var close_points = offset_points.duplicate()# 闭合if close_path:close_points.append(close_points[0])if dash>0.0:  # 虚线间隔大于0for seg in segments(close_points):canvas.draw_dashed_line(seg[0],seg[1],border_color,border_width,dash)passelse:canvas.draw_polyline(close_points,border_color,border_width)   # 绘制实现闭合轮廓# 5.绘制顶点if draw_points:for p in points:# 绘制圆点canvas.draw_circle(p,point_r,point_fill_color)# 绘制边线canvas.draw_arc(p,point_r,0,TAU,TAU * point_r,point_border_color,point_border_width/2.0,true)# 6.绘制位置点if draw_position:var line_count = 4var ang = 360.0/float(line_count)  # 每次旋转角度for i in range(line_count):var p1 = offsetvar p2 = p1 + pVector2(ang * i,5)canvas.draw_line(p1,p2,border_color,border_width)# 获取图形的矩形
func get_rect() -> Rect2:# 对所有点进行位移变换var points = Transform2D().translated(offset) * points# 拆分出X坐标和Y坐标数组var x_arr = []var y_arr = []for p in points:x_arr.append(p.x)y_arr.append(p.y)# 最小值构成Rect2的offsetvar pos = Vector2(x_arr.min(),y_arr.min())# 最大值 - pos = Rect2 的 sizevar siz = Vector2(x_arr.max(),y_arr.max()) - posprint(pos,"   ",siz)return Rect2(pos,siz)# ============================== 子类通用函数 ==============================
# 极坐标点函数 - 通过角度和长度定义一个点
func pVector2(angle:float = 0.0,length:float =0.0) -> Vector2:var dir = Vector2.RIGHT.rotated(deg_to_rad(angle))return dir * length# points的点按顺序两两相连的所有线段
func segments(points:PackedVector2Array) -> Array[PackedVector2Array]:var arr:Array[PackedVector2Array]if points.size() >1:  # 至少有两个点for i in range(points.size() -1):var seg:PackedVector2Array = [points[i],points[i+1]]arr.append(seg)return arr

代码改造要点:

  • 属性:单纯的类设计时,属性不能也不需要被设计为导出变量形式,而自定义资源类型,其参数大多数都需要设置为导出变量,用于方便在编辑器检视器面板修改
# 点集合
@export var points:PackedVector2Array = []:set(val):points = valemit_changed() # 触发资源的changed信号
  • emit_changed()是触发资源实例的changed信号,在自定义节点或场景中我们可以连接此信号,用于在资源的属性修改后,进行一定的处理

CanvasRect(矩形)

# =============================================
# 名称:CanvasRect
# 类型:类
# 描述:CanvasItem绘图函数图形类 - 矩形
# 作者:巽星石
# 创建时间:202472716:07:23
# 最后修改时间:20249523:08:37
# =============================================
@tool
class_name CanvasRect extends CanvasShape
# ============================== 属性 ==============================# 宽度
@export var width:float = 50:set(val):width = valupdate_points()emit_changed()
# 高度
@export var height:float = 50:set(val):height = valupdate_points()emit_changed()func _init() -> void:close_path = trueupdate_points()# ============================== 方法 ==============================
# 更新点集
func update_points() -> void:points.clear()var center = Vector2(width,height)/2.0var half_width = Vector2(width,0)/2.0var half_height = Vector2(0,height)/2.0# 求点points.append(offset - center)points.append(offset - half_height + half_width)points.append(offset + center)points.append(offset - half_width + half_height)func draw(canvas:CanvasItem) -> void:# 绘制super.draw(canvas)

CanvasRegularPolygon(正多边形)

# =============================================
# 名称:CanvasRegularPolygon
# 类型:类
# 描述:CanvasItem绘图函数图形类 - 正多边形
# 作者:巽星石
# 创建时间:202472516:03:41
# 最后修改时间:20249523:09:18
# =============================================
@tool
class_name CanvasRegularPolygon extends CanvasShape
# ============================== 属性 ==============================
## 正多边形的外接圆半径
@export var r:float = 30:set(val):r = valupdate_points()emit_changed()
## 正多边形的边数
@export_range(3,1000,1,"suffix:边") var edges:int = 3:set(val):edges = valupdate_points()emit_changed()
## 起始角度(与X轴正方向夹角)
@export_range(-360,360,1,"degrees") var start_angle:= 0.0:set(val):start_angle = valupdate_points()emit_changed()func _init() -> void:close_path = trueupdate_points()# ============================== 方法 ==============================
# 更新点集
func update_points() -> void:points.clear()# 求点var ang = 360.0/float(edges) # 每次旋转角度for i in range(edges):points.append(pVector2(i * ang + start_angle,r))func draw(canvas:CanvasItem) -> void:# 绘制super.draw(canvas)

CanvasLine(线段)

# =============================================
# 名称:CanvasLine
# 类型:类
# 描述:CanvasItem绘图函数图形类 - 线段
# 作者:巽星石
# 创建时间:202472716:33:28
# 最后修改时间:20249523:10:27
# =============================================
@tool
class_name CanvasLine extends CanvasShape
# ============================== 属性 ==============================# 起点
@export var p1:=Vector2():set(val):p1 = valupdate_points()emit_changed()# 起点
@export var p2:=Vector2(100,0):set(val):p2 = valupdate_points()emit_changed()func _init() -> void:border_color = Color.WHITEupdate_points()# ============================== 方法 ==============================
# 更新点集
func update_points() -> void:points.clear()# 求点points.append(p1)points.append(p2)func draw(canvas:CanvasItem) -> void:# 绘制super.draw(canvas)

测试场景

场景根节点代码如下:

@tool
extends Node2D# 修改shape属性时,连接CanvasShape资源的changed信号处理函数
# 仅在已经存在赋值时
@export var shape:CanvasShape:set(val):shape = valqueue_redraw()	_enter_tree()# 加载场景时,连接CanvasShape资源的changed信号处理函数
# 仅在已经存在赋值时
func _enter_tree() -> void:if shape:shape.changed.connect(func():queue_redraw()	)# 调用CanvasShapedraw()方法,绘制
func _draw() -> void:if shape:shape.draw(self)

此时便可以在检视器面板选择相应的CanvasShape资源及其子类型了。赋值shape属性后,会在场景根节点按默认参数绘制图形,修改资源的属性时,根节点会动态进行修改。

初期未自定义图标


自定义图标

在InkScape中简单绘制一个大致正方形区域的图标,导出图标到Godot项目中。可以是SVG或PNG格式。

在自定义资源或节点顶部用@icon("图标路径")语法可以设定图标。例如:

@icon("res://lib/绘图相关/CanvasShape/icons/CanvasShape.png")

此时,就可以在检视器面板看到自定义类的图标:

自定义图标后的资源


ShapeNode2D

通过为上面测试场景的根节点设定class_name,就可以创建自定义的Node2D节点。这里我创建了一个专门显示CanvasShape资源的ShapeNode2D节点。

# =============================================
# 名称:ShapeNode2D
# 类型:Node2D
# 描述:专用于显示CanvasShape资源图形的自定义2D节点
# 作者:巽星石
# 创建时间:20249520:04:05
# 最后修改时间:20249523:03:01
# =============================================
@tool
@icon("res://lib/绘图相关/CanvasShape/icons/CanvasShape.png")
class_name ShapeNode2D extends Node2D# 修改shape属性时,连接CanvasShape资源的changed信号处理函数
# 仅在已经存在赋值时
@export var shape:CanvasShape:set(val):shape = valqueue_redraw()_enter_tree()# 加载场景时,连接CanvasShape资源的changed信号处理函数
# 仅在已经存在赋值时
func _enter_tree() -> void:if shape:shape.changed.connect(func():queue_redraw()	)# 调用CanvasShapedraw()方法,绘制
func _draw() -> void:if shape:shape.draw(self)

ShapeNode2D实例化测试

  • ShapeNode2D只有一个shape属性,通过设定CanvasShape资源及其子类型,然后设定其属性就可以动态的绘制出一些参数化的2D几何图形。

为shape属性设定CanvasShape资源实例

  • 基于继承的优势:因为ShapeNode2D继承自Node2D,所以它天然的可以使用Node2D类型及其继承链上的所有类型的属性、方法和信号。当然也就包括了Node2D的位移、旋转、缩放等。

ShapePolygon2D

以同样的思路,我们可以设计一个Polygon2D的扩展类型节点。

# =============================================
# 名称:ShapePolygon2D
# 类型:Polygon2D拓展类型
# 描述:专用于显示CanvasShape资源图形的自定义Polygon2D节点
# 作者:巽星石
# 创建时间:20249523:59:17
# 最后修改时间:20249600:02:23
# =============================================
@tool
class_name ShapePolygon2D extends Polygon2D# 修改shape属性时,连接CanvasShape资源的changed信号处理函数
# 仅在已经存在赋值时
@export var shape:CanvasShape:set(val):shape = valupdate_polygon()_enter_tree()# =================================== 虚函数 ===================================	
func _init():update_polygon()# 加载场景时,连接CanvasShape资源的changed信号处理函数
# 仅在已经存在赋值时
func _enter_tree() -> void:if shape:shape.changed.connect(func():update_polygon())
# =================================== 方法 ===================================
# 更新形状
func update_polygon():polygon = shape.points

ShapePolygon2D测试

总结

  • 通过将CanvasItem绘制的图形编写为自定义类CanvasShape,完成了第一次简单的进化
  • 而将CanvasShape变成自定义资源类型,则完成了二次进化,它将可以用于Node2D、Control、Polygon2D以及其他自定义节点上,也可以单独用于代码形式的CanvasItem绘图
  • 通过在类、场景节点或自定义节点中设定Array[CanvasShape]的导出变量,我们将可以在检视器面板设定和维护多个CanvasShape的列表。

这篇关于【Godot4.3】CanvasShape资源化改造的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1142255

相关文章

【Godot4.3】多边形的斜线填充效果基础实现

概述 图案(Pattern)填充是一个非常常见的效果。其中又以斜线填充最为简单。本篇就探讨在Godot4.3中如何使用Geometry2D和CanvasItem的绘图函数实现斜线填充效果。 基础思路 Geometry2D类提供了多边形和多边形以及多边形与折线的布尔运算。按照自然的思路,多边形的斜线填充应该属于“多边形与折线的布尔运算”范畴。 第一个问题是如何获得斜线,这条斜线应该满足什么样

改造了一个流量阈值自动关机的脚本

改造后的脚本地址:https://raw.githubusercontent.com/BiuBIu-Ka/traffic_monitor/main/main.sh 优化的问题: 优化脚本运行多次会一直叠加流量的问题优化服务器重启后流量记录值清空的问题增加一个小日志系统 wget https://raw.githubusercontent.com/BiuBIu-Ka/traffic_monit

无需更换摄像头,无需施工改造,降低智能化升级成本的智慧工业开源了。

智慧工业视觉监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。 项目搭建地址 项目开源地址:yihecode-server 本项目基于ai场景而开发,提供算法模型管理、摄像头管

信也持续构建集群容器化改造之路

1. 前言 随着应用构建需求增加以及新构建场景引入,公司对构建系统的扩展性、稳定性要求日益提高。多语言构建(如Golang、Java、Python、Node.js 等)所依赖的环境,部署在同一台物理机上时,使构建机环境维护困难;并且多应用同时在一台机器上构建会相互影响;在传统的构建机主从模式下,单一的Master 构建节点会成为系统单点故障源,导致整个构建集群不可用。 通过行业方案调研,

WordPressMIP主题下载,WordPress MIP与百度熊掌号改造接入(V3.4.1)

WordPressMIP主题,是基于熊掌号最新移动端主题,根据百度MIP开发规范升级改造而成,移除冗余代码,完美符合百度MIP规范的一款WordPress移动端主题。   WordPress快速引入百度MIP其实也挺简单,懂代码的人可以直接根据百度MIP官网的规范和验证提示进行原有移动端的改造,不过需要说一点的就是,那些使用自适应的网站引入MIP估计是有点繁琐,甚至基本不太可能,与其改造原

【Godot4.3】基于纯绘图函数自定义的线框图控件

概述 同样是来自2023年7月份的一项实验性工作,基于纯绘图函数扩展的一套线框图控件。初期只实现了三个组件,矩形、占位框和垂直滚动条。 本文中的三个控件类已经经过了继承化的修改,使得代码更少。它们的继承关系如下: 源代码 WireFrameRect(矩形) # ========================================================# 名

android 改造TextView使上下左右Drawble宽高可调

1、首先在attrs.xml中声明自定义属性 <declare-styleable name="DrawableEditView"><!-- 设置top图片的宽度 --><attr name="edit_drawableTopWidth" format="dimension" /><!-- 设置top图片的高度 --><attr name="edit_drawableTopHeight" f

如何将vim改造成强大的代码阅读器

最近在接触C/C++编程,一般是在公司的远程服务器阅读和编写代码,这就会涉及C/C++的代码阅读器的问题。通过请教和调研,使用比较广泛的方式是在vim上添加插件,增强vim的功能。 经过比较和分析,使用比较广泛的插件是Ctags和Taglist两个插件。 简单说明一下这两个插件的关系。 插件1:Ctag:通过这个插件为程序中的变量、函数、类生成对应的tag标签。可以理解成Map的形式,

【Godot4.3】MarkDown编辑和控件事实渲染

概述 这是本人2024年5月份左右编写的一个简易的MarkDown编辑和渲染测试项目,基于自己编写的MarkDown解析和生成类MDdoc编写。之前是作为一个试验性的内容混乱的放置在另一个测试项目中,现在独立为一个单独项目。因为测验成功后就一直没改动,所以这仍然是一个很初期的版本。 项目核心 它的核心是有两部分: MDdoc类:一个MarkDown纯文本解析类,可以将MarkDown文

SpringBoot项目中mybatis执行sql很慢的排查改造过程(Interceptor插件、fetchSize、隐式转换等)

刚入职公司,就发现公司项目跑sql特别慢,差不多一万条数据插入到数据库要5秒以上(没有听错,就是这个速度),查询修改删除也是特别慢。直到22年年底实在是受不了了,我就去排查了一下。 用的是Oracle数据库,mybatis、mybatis plus,其中mybatis是引入的平台的依赖。平台封装了一些工具和插件。 做个对照试验 首先为了做对照试验,自己新建了一个SpringBoot项目T,里面