【godot4.4】布局函数库Layouts

概述

为了方便编写一些自定义容器和控件、节点时方便元素布局,所以编写了一套布局的求取函数,统一放置在一个名为Layouts的静态函数库中。

本文介绍我自定义的一些布局计算和实现以及函数编写的思路,并提供完整的函数库代码(持续更行)。

因为正在编写中,所以可能有部分布局还未实现或正在经历修改。

关于布局的基础思想

  • 布局的本质是排列矩形,在Godot中也就是计算Rect2
  • Rect2可以并列、重叠以及嵌套,以对应各种不同的布局方式
  • 布局是一种参数化的抽象,不仅仅可以用于自定义容器,也可以结合CanvasItem绘图函数,用于创建自定义控件和2D节点的子元素或参数元素布局

获得设定内外边距后的矩形

通过封装Rect2提供的边距偏移方法,就可以获得设定内边距或外边距的矩形。

一般用于控件或容器,只需要设计内边距。

在Godot的StyleBox中,内边距不叫padding,而是被称为content_margin。所以在设计中可能并不特意区分paddingmargin的称谓。

内边距盒模型:
内边距盒模型
外边距盒模型:
外边距盒模型
两个盒模型中:

  • 实线:为初始的矩形
  • 虚线:为设定边距后偏移得到的矩形

内边距矩形求取函数

这里我只实现设定内边距的矩形求取函数。

# 求设定内边距的矩形
static func padding_rect(
	rect:Rect2,        # 外框矩形
	top:float = 0.0,   # 顶部边距
	right:float = 0.0, # 右侧边距
	bottom:float = 0.0,# 底部边距
	left:float = 0.0,  # 左侧边距
) -> Rect2: 
	# 通过反向偏移边距,获得内容区矩形
	# min限定只能向内进行偏移
	var content_rect:Rect2 = rect.grow_individual(
		min(-left,0),
		min(-top,0),
		min(-right,0),
		min(-bottom,0),
	)
	return content_rect

Grid布局

均分网格布局

Grid布局可以作为一个核心布局,均分布局可以被取代。

  • columns:指定列数
  • rows:指定行数
  • col_gap:列间距
  • row_gap:行间距
  • margin_top:顶部内边距
  • margin_bottom:底部内边距
  • margin_left:左侧内边距
  • margin_right:右侧内边距

求解思路:

  • 根据外框矩形和边距,算出内容区域的矩形;
  • 根据行数和列数,以及行列间隔,获得左上角第一个单元格大小,然后偏移获得其他矩形。

均分网格布局

# 均分网格布局
static func grid(
	rect:Rect2,   # 外框矩形
	# =========== 基础参数 ===========
	columns:int,  # 列数
	rows:int,     # 行数
	col_gap:float = 0.0,      # 列间距
	row_gap:float = 0.0,      # 行间距
	# =========== 边距设定 ===========
	margin_top:float = 0.0,   # 顶部边距
	margin_bottom:float = 0.0,# 底部边距
	margin_left:float = 0.0,  # 左侧边距
	margin_right:float = 0.0, # 右侧边距
) -> Array[Rect2]:
	var rects:Array[Rect2]
	# 通过反向偏移边距,获得内容区矩形
	# min限定只能向内进行偏移
	var content_rect:Rect2 = rect.grow_individual(
		min(-margin_left,0),
		min(-margin_top,0),
		min(-margin_right,0),
		min(-margin_bottom,0),
	)
	# 减除行列间距后内容区域的尺寸
	var calc_size = content_rect.size - Vector2(col_gap,row_gap) * Vector2(max(columns - 1,0),max(rows -1,0)) 
	# 左上角第一个单元格矩形
	var cell_rect:Rect2 = Rect2(
		content_rect.position,
		calc_size/Vector2(columns,rows)
	)
	# 单个偏移
	var trans:Vector2 = cell_rect.size + Vector2(col_gap,row_gap)
	# 计算出所有单元格的矩形
	for x in range(columns):
		for y in range(rows):
			rects.append(translate(Vector2(x,y) * trans) * cell_rect)
	return rects

测试代码:

@tool
extends Control

@export var image:Texture2D:
	set(val):
		image = val
		queue_redraw()
## 行数
@export var rows:int = 1:
	set(val):
		rows = val
		queue_redraw()

## 列数
@export var cols:int = 1:
	set(val):
		cols = val
		queue_redraw()

## 列间距
@export var col_gap:float=0.0:
	set(val):
		col_gap = val
		queue_redraw()

## 行间距
@export var row_gap:float=0.0:
	set(val):
		row_gap = val
		queue_redraw()

## 顶部边距
@export var margin_top:float=0.0:
	set(val):
		margin_top = val
		queue_redraw()

## 顶部边距
@export var margin_bottom:float=0.0:
	set(val):
		margin_bottom = val
		queue_redraw()

## 顶部边距
@export var margin_left:float=0.0:
	set(val):
		margin_left = val
		queue_redraw()

## 顶部边距
@export var margin_right:float=0.0:
	set(val):
		margin_right = val
		queue_redraw()

func _draw() -> void:
	var rect = get_rect() * get_transform()
	var rects:Array[Rect2] = Layouts.grid(
		rect,cols,rows,col_gap,row_gap,
		margin_top,margin_bottom,margin_left,margin_right
		)
	# 绘制图片
	for rc in rects:
		draw_texture_rect(image,rc,false)

测试效果:

比例布局

给定多个数字,每一格占总数分之自己。比如(1,2,3)第一格占1/6,第二格2/6,第三格占3/6。垂直版本类似。

比例布局是非均分网格布局的基础。

均分布局

基于均分网格布局,可以生成一些常用的均分布局,以简化参数。

水平和垂直居中

中间宽度固定,上下或左右居中的布局。

在这里插入图片描述

ABA布局

两端宽度固定,中间自适应的布局。

在这里插入图片描述

特殊布局

类紫微斗数盘布局

紫微斗数盘布局

边角悬浮定位布局

头图文档布局

可以拆解为边悬浮定位布局+水平居中布局。

头图文档布局

函数库完整代码

# ========================================================
# 名称:Layouts
# 类型:静态函数库
# 简介:提供布局函数
# 作者:巽星石
# Godot版本:v4.4.stable.steam [4c311cbee]
# 创建时间:20253320:27:59
# 最后修改时间:20253820:06:59
# ========================================================
class_name Layouts


# ============================ 基础函数和辅助方法 ============================
# 偏移
static func translate(offset: Vector2) -> Transform2D:
	return Transform2D().translated(offset)

# 求设定内边距的矩形
static func padding_rect(
	rect:Rect2,        # 外框矩形
	top:float = 0.0,   # 顶部边距
	right:float = 0.0, # 右侧边距
	bottom:float = 0.0,# 底部边距
	left:float = 0.0,  # 左侧边距
) -> Rect2: 
	# 通过反向偏移边距,获得内容区矩形
	# min限定只能向内进行偏移
	var content_rect:Rect2 = rect.grow_individual(
		min(-left,0),
		min(-top,0),
		min(-right,0),
		min(-bottom,0),
	)
	return content_rect


# ============================ 布局计算求取函数 ============================

# =========================== 【水平和垂直居中布局】
# 水平定宽居中布局
static func HCenter(
	rect:Rect2,           # 外框矩形
	width:float,          # 固定宽度
	padding_top:=0.0,     # 上边距
	padding_bottom:=0.0,  # 下边距
) -> Rect2: 
	var dw = (rect.size.x - width)/2.0
	return padding_rect(
		rect,padding_top,dw,padding_bottom,dw
	)

# 垂直定宽居中布局
static func VCenter(
	rect:Rect2,           # 外框矩形
	height:float,         # 固定高度
	padding_left:=0.0,     # 上边距
	padding_right:=0.0,  # 下边距
) -> Rect2: 
	var dh = (rect.size.y - height)/2.0
	return padding_rect(
		rect,dh,padding_right,dh,padding_left
	)

# 水平垂直定尺寸居中布局
static func Center(
	rect:Rect2,           # 外框矩形
	width:float,          # 固定宽度
	height:float,         # 固定高度
) -> Rect2: 
	var dw = (rect.size.x - width)/2.0
	var dh = (rect.size.y - height)/2.0
	return padding_rect(
		rect,dh,dw,dh,dw
	)


# =========================== 【均分布局】
# 均分网格布局
static func grid(
	rect:Rect2,   # 外框矩形
	# =========== 基础参数 ===========
	columns:int,  # 列数
	rows:int,     # 行数
	col_gap:float = 0.0,      # 列间距
	row_gap:float = 0.0,      # 行间距
	# =========== 边距设定 ===========
	margin_top:float = 0.0,   # 顶部边距
	margin_right:float = 0.0, # 右侧边距
	margin_bottom:float = 0.0,# 底部边距
	margin_left:float = 0.0,  # 左侧边距
) -> Array[Rect2]:
	var rects:Array[Rect2]
	# 获取内容区矩形
	var content_rect:Rect2 = padding_rect(
		rect,margin_top,margin_right,margin_bottom,margin_left,
	)
	# 减除行列间距后内容区域的尺寸
	var calc_size = content_rect.size - Vector2(col_gap,row_gap) * Vector2(max(columns - 1,0),max(rows -1,0)) 
	# 左上角第一个单元格矩形
	var cell_rect:Rect2 = Rect2(
		content_rect.position,
		calc_size/Vector2(columns,rows)
	)
	# 单个偏移
	var trans:Vector2 = cell_rect.size + Vector2(col_gap,row_gap)
	# 计算出所有单元格的矩形
	for x in range(columns):
		for y in range(rows):
			rects.append(translate(Vector2(x,y) * trans) * cell_rect)
	return rects


# 上下均分布局
static func top_down(
	rect:Rect2,   # 外框矩形
	# =========== 基础参数 ===========
	gap:float = 0.0,      # 行间距
	# =========== 边距设定 ===========
	margin_top:float = 0.0,   # 顶部边距
	margin_bottom:float = 0.0,# 底部边距
	margin_left:float = 0.0,  # 左侧边距
	margin_right:float = 0.0, # 右侧边距
) -> Array[Rect2]:
	return grid(
		rect,1,2,0,gap,
		margin_top,margin_bottom,margin_left,margin_right
		)

# 左右均分布局
static func left_right(
	rect:Rect2,   # 外框矩形
	# =========== 基础参数 ===========
	gap:float = 0.0,      # 列间距
	# =========== 边距设定 ===========
	margin_top:float = 0.0,   # 顶部边距
	margin_bottom:float = 0.0,# 底部边距
	margin_left:float = 0.0,  # 左侧边距
	margin_right:float = 0.0, # 右侧边距
) -> Array[Rect2]:
	return grid(
		rect,2,1,gap,0,
		margin_top,margin_bottom,margin_left,margin_right
		)


# 四均分布局
static func four_split(
	rect:Rect2,   # 外框矩形
	# =========== 基础参数 ===========
	col_gap:float = 0.0,      # 列间距
	row_gap:float = 0.0,      # 行间距
	# =========== 边距设定 ===========
	margin_top:float = 0.0,   # 顶部边距
	margin_bottom:float = 0.0,# 底部边距
	margin_left:float = 0.0,  # 左侧边距
	margin_right:float = 0.0, # 右侧边距
) -> Array[Rect2]:
	return grid(
		rect,2,2,col_gap,row_gap,
		margin_top,margin_bottom,margin_left,margin_right
		)

# 九均分布局 (九宫格)
static func nine_split(
	rect:Rect2,   # 外框矩形
	# =========== 基础参数 ===========
	col_gap:float = 0.0,      # 列间距
	row_gap:float = 0.0,      # 行间距
	# =========== 边距设定 ===========
	margin_top:float = 0.0,   # 顶部边距
	margin_bottom:float = 0.0,# 底部边距
	margin_left:float = 0.0,  # 左侧边距
	margin_right:float = 0.0, # 右侧边距
) -> Array[Rect2]:
	return grid(
		rect,3,3,col_gap,row_gap,
		margin_top,margin_bottom,margin_left,margin_right
		)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/983519.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Windows下配置Conda环境路径

问题描述: 安装好Conda之后,创建好自己的虚拟环境,同时下载并安装了Pycharm,但在Pycharm中找不到自己使用Conda创建好的虚拟环境。显示“Conda executable is not found” 解决办法(依次尝试以下) 起初怀…

OpenHarmony子系统开发编译构建指导

OpenHarmony子系统开发编译构建指导 概述 OpenHarmony编译子系统是以GN和Ninja构建为基座,对构建和配置粒度进行部件化抽象、对内建模块进行功能增强、对业务模块进行功能扩展的系统,该系统提供以下基本功能: 以部件为最小粒度拼装产品和独…

leetcode日记(80)复原IP地址

只能说之前动态规划做多了,看到就想到动态规划,然后想想其实完全不需要,回溯法就行了。 一开始用了很多莫名其妙的代码,写的很复杂……(主要因为最后不能加‘.’)其实想想只要最后加入vector时去掉最后一个…

LINUX网络基础 [五] - HTTP协议

目录 HTTP协议 预备知识 认识 URL 认识 urlencode 和 urldecode HTTP协议格式 HTTP请求协议格式 HTTP响应协议格式 HTTP的方法 HTTP的状态码 ​编辑HTTP常见Header HTTP实现代码 HttpServer.hpp HttpServer.cpp Socket.hpp log.hpp Makefile Web根目录 H…

【A2DP】SBC 编解码器互操作性要求详解

目录 一、SBC编解码器互操作性概述 二、编解码器特定信息元素(Codec Specific Information Elements) 2.1 采样频率(Sampling Frequency) 2.2 声道模式(Channel Mode) 2.3 块长度(Block Length) 2.4 子带数量(Subbands) 2.5 分配方法(Allocation Method) 2…

电脑内存智能监控清理,优化性能的实用软件

软件介绍 Memory cleaner是一款内存清理软件。功能很强,效果很不错。 Memory cleaner会在内存用量超出80%时,自动执行“裁剪进程工作集”“清理系统缓存”以及“用全部可能的方法清理内存”等操作,以此来优化电脑性能。 同时,我…

基于multisim的花样彩灯循环控制电路设计与仿真

1 课程设计的任务与要求 (一)、设计内容: 设计一个8路移存型彩灯控制器,基本要求: 1. 8路彩灯能演示至少三种花型(花型自拟); 2. 彩灯用发光二极管LED模拟; 3. 选做…

Axure常用变量及使用方法详解

点击下载《Axure常用变量及使用方法详解.pdf》 摘要 Axure RP 作为一款领先的前端原型设计工具,提供了全面的 变量 和 函数 系统,以支持复杂的交互设计和动态内容展示。本文将从专业角度详细解析 Axure 中的 全局变量、中继器数据集变量/函数、元件变量…

MySql的安装及数据库的基本操作命令

1.MySQL的安装 1.1进入MySQL官方网站 1.2点击下载 1.3下拉选择MySQL社区版 1.4选择你需要下载的版本及其安装的系统和下载方式 直接安装以及压缩包 建议选择8.4.4LST LST表明此版本为长期支持版 新手建议选择红框勾选的安装方式 1.5 安装包下载完毕之后点击安装 2.数据库…

树莓派5首次开机保姆级教程(无显示器通过VNC连接树莓派桌面)

第一次开机详细步骤 步骤一:树莓派系统烧录1 搜索打开烧录软件“Raspberry Pi Imager”2 选择合适的设备、系统、SD卡3 烧录配置选项 步骤二:SSH远程树莓派1 树莓派插电2 网络连接(有线或无线)3 确定树莓派IP地址 步骤三&#xff…

分布式锁—7.Curator的分布式锁

大纲 1.Curator的可重入锁的源码 2.Curator的非可重入锁的源码 3.Curator的可重入读写锁的源码 4.Curator的MultiLock源码 5.Curator的Semaphore源码 1.Curator的可重入锁的源码 (1)InterProcessMutex获取分布式锁 (2)InterProcessMutex的初始化 (3)InterProcessMutex.…

电脑睡眠智能管控:定时、依状态灵活调整,多模式随心选

软件介绍 今天要给大家介绍一款十分实用的软件——DontSleep,从名字就能看出,它的核心功能之一是阻止电脑进入睡眠状态,不过它的能耐可远不止于此,还具备强大的定时以及根据电脑实时状况灵活调整的功能。 这款软件采用绿色单文件…

装饰器模式--RequestWrapper、请求流request无法被重复读取

目录 前言一、场景二、原因分析三、解决四、更多 前言 曾经遇见这么一段代码,能看出来是把request又重新包装了一下,核心信息都不会改变 后面了解到这叫 装饰器模式(Decorator Pattern) :也称为包装模式(Wrapper Pat…

C++20 格式化库:强大的字符串格式化工具

文章目录 格式化语法常见用法1. 填充和对齐2. 数值格式化3. 进制格式化4. 自定义类型 示例代码注意事项 C20 的格式化库是一个强大的工具,用于处理字符串的格式化操作。它提供了类似于 Python 中 str.format() 的功能,但语法和用法更符合 C 的风格。以下…

Linux基础--文件权限+软件包管理+管道符

目录 基础权限 更改文件权限 使用命令:chmod 更改文件属主和数组 使用命令: chown 权限掩码 使用命令:umask 高级权限 软件包管理 使用命令: rpm 使用命令: yum 管道符,重定向 基础权限 文件基础权限表 符号含义数字r读权限4w写权限2x执行权限1 更改文件…

css画出带圆角平行四边形效果

使用css画出平行四边形效果如下图 HTML代码 <div class"badge"><span>营业中</span> </div> 关键代码&#xff1a; transform: skewX(-15deg); /* 让元素倾斜&#xff0c;形成平行四边形的视觉效果 */ 如果倾斜的元素里面需要放文字&…

postman接口请求中的 Raw是什么

前言 在现代的网络开发中&#xff0c;API 的使用已经成为数据交换的核心方式之一。然而&#xff0c;在与 API 打交道时&#xff0c;关于如何发送请求体&#xff08;body&#xff09;内容类型的问题常常困扰着开发者们&#xff0c;尤其是“raw”和“json”这两个术语之间的区别…

Gartner:数据安全平台DSP提升数据流转及使用安全

2025 年 1 月 7 日&#xff0c;Gartner 发布“China Context&#xff1a;Market Guide for Data Security Platforms”&#xff08;《数据安全平台市场指南——中国篇》&#xff0c;以下简称指南&#xff09;&#xff0c;报告主要聚焦中国数据安全平台&#xff08;Data Securit…

记录一次wifi版有人物联串口服务器调试经过

1、首先买了一个华为的wifi路由器&#xff0c;连接上以后&#xff0c;设置好网络名字和wifi密码 2、用网线连接串口服务器&#xff0c;通过192.168.1.1登录&#xff0c;进行配置 找到无线客户端配置&#xff0c;先在基本配置中打开5G配置&#xff0c;然后再去5.8G配置中设置 …

百货店的诞生与现代商业革命:结合开源AI智能客服、AI智能名片与S2B2C商城小程序的新视角

摘要&#xff1a;本文深入探讨了百货店作为现代商业革命的标志性事件&#xff0c;其出现对销售方式、经营方式、组织管理三个方面的根本性变革。同时&#xff0c;本文也展望了在数字化时代背景下&#xff0c;开源AI智能客服、AI智能名片以及S2B2C商城小程序等新兴技术如何为传统…