Godot 4 源码分析 - 练手 - 和谐共生

news2024/12/30 2:19:01

今天看到一个微信视频,和谐共生,大概效果如下

https://live.csdn.net/v/306826

研究这么长时间的Godot,今天试试能否实现上述效果

粗看一下,这个效果实现分几步:

1. 画圆,并确定多个圆的位置规律

2. 动点,并确定各动点的运动规律

3. 综合调试

1. 画圆

这个应该是比较简单的,直观感觉是要画出来。直接新建一个工程draw,根场景为Node2D,名为Circle,绑定脚本circle.gd。下来就直接处理circle.gd

从学习理解来看,应该是重写_draw()函数,直接调用draw_circle函数试试

func _draw():	
	draw_circle(Vector2(300, 300), 150, Color.WHITE);

结果出来了,好象不难。 

但好象是需要画空心圆,但看Godot源码中,draw_circle函数居然只有三个参数,分别为中心点坐标、半径长度、颜色。

void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color) {
	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");

	RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
}

 跟踪源码canvas_item_add_circle

void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) {
	Item *canvas_item = canvas_item_owner.get_or_null(p_item);
	ERR_FAIL_COND(!canvas_item);

	Item::CommandPolygon *circle = canvas_item->alloc_command<Item::CommandPolygon>();
	ERR_FAIL_COND(!circle);

	circle->primitive = RS::PRIMITIVE_TRIANGLES;

	Vector<int> indices;
	Vector<Vector2> points;

	static const int circle_points = 64;

	points.resize(circle_points);
	Vector2 *points_ptr = points.ptrw();
	const real_t circle_point_step = Math_TAU / circle_points;

	for (int i = 0; i < circle_points; i++) {
		float angle = i * circle_point_step;
		points_ptr[i].x = Math::cos(angle) * p_radius;
		points_ptr[i].y = Math::sin(angle) * p_radius;
		points_ptr[i] += p_pos;
	}

	indices.resize((circle_points - 2) * 3);
	int *indices_ptr = indices.ptrw();

	for (int i = 0; i < circle_points - 2; i++) {
		indices_ptr[i * 3 + 0] = 0;
		indices_ptr[i * 3 + 1] = i + 1;
		indices_ptr[i * 3 + 2] = i + 2;
	}

	Vector<Color> color;
	color.push_back(p_color);
	circle->polygon.create(indices, points, color);
}

搞明白了,画圆其实就是在内部用多边形实现。感觉

circle->primitive = RS::PRIMITIVE_TRIANGLES;

 是控制效果的,直接看定义:

	enum PrimitiveType {
		PRIMITIVE_POINTS,
		PRIMITIVE_LINES,
		PRIMITIVE_LINE_STRIP,
		PRIMITIVE_TRIANGLES,
		PRIMITIVE_TRIANGLE_STRIP,
		PRIMITIVE_MAX,
	};

那就挨个测试一下,前5个分别对应以下效果

感觉都不是想要的效果。再看这些枚举量,感觉有点熟悉,好象在OpenGL中有类似的定义。难道Godot没有画空心圆的方法。

当然不是,一种方法是画一个实心圆,然后再以小一点的半径再用背景色画一个实心圆,最终感觉是一个空心圆。比如

	draw_circle(Vector2(300, 300), 150, Color.WHITE);
	draw_circle(Vector2(300, 300), 149, Color.BLACK);

结果 

为了更像一些,先把背景也画成黑色

	draw_rect(Rect2(0, 0, get_viewport_rect().size.x, get_viewport_rect().size.y), Color.BLACK)
	draw_circle(Vector2(300, 300), 150, Color.WHITE);
	draw_circle(Vector2(300, 300), 149, Color.BLACK);

得到结果,感觉是个空心圆了。

 

但这种方式是伪空心圆,画两个部分重叠的圆,就发现问题了

	draw_rect(Rect2(0, 0, get_viewport_rect().size.x, get_viewport_rect().size.y), Color.BLACK)
	draw_circle(Vector2(300, 300), 150, Color.WHITE);
	draw_circle(Vector2(300, 300), 149, Color.BLACK);
	draw_circle(Vector2(450, 300), 150, Color.WHITE);
	draw_circle(Vector2(450, 300), 149, Color.BLACK);

 所以这种方法行不通。

研究一下源码,画图的各API函数

	void draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = -1.0, real_t p_dash = 2.0, bool p_aligned = true);
	void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false);
	void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false);
	void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = -1.0, bool p_antialiased = false);
	void draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false);
	void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = -1.0);
	void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = -1.0);
	void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = -1.0);
	void draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color);
	void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1));
	void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
	void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false);
	void draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0, double p_scale = 1.0);
	void draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1));
	void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
	void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>());
	void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>());
	void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>());

	void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1));
	void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture);

	void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = Font::DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1.0, 1.0, 1.0), BitField<TextServer::JustificationFlag> p_jst_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
	void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = Font::DEFAULT_FONT_SIZE, int p_max_lines = -1, const Color &p_modulate = Color(1.0, 1.0, 1.0), BitField<TextServer::LineBreakFlag> p_brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, BitField<TextServer::JustificationFlag> p_jst_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;

	void draw_string_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_size = 1, int p_font_size = Font::DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1.0, 1.0, 1.0), BitField<TextServer::JustificationFlag> p_jst_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
	void draw_multiline_string_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = Font::DEFAULT_FONT_SIZE, int p_max_lines = -1, int p_size = 1, const Color &p_modulate = Color(1.0, 1.0, 1.0), BitField<TextServer::LineBreakFlag> p_brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, BitField<TextServer::JustificationFlag> p_jst_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;

	void draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, int p_font_size = Font::DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1.0, 1.0, 1.0)) const;
	void draw_char_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, int p_font_size = Font::DEFAULT_FONT_SIZE, int p_size = 1, const Color &p_modulate = Color(1.0, 1.0, 1.0)) const;

	void draw_set_transform(const Point2 &p_offset, real_t p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0));
	void draw_set_transform_matrix(const Transform2D &p_matrix);
	void draw_animation_slice(double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset = 0);
	void draw_end_animation();

感觉draw_arc可能有用,试下

	draw_rect(Rect2(0, 0, get_viewport_rect().size.x, get_viewport_rect().size.y), Color.BLACK)
	draw_arc(Vector2(300, 300), 150, 0, PI * 2, 200, Color.WHITE, -1, true);
	draw_arc(Vector2(450, 300), 150, 0, PI * 2, 200, Color.WHITE, -1, true);

结果

可行。

那就统一改造。因为可能画实心圆,也可能画空心圆,所以实现函数

func drawCircle(pos, radius, color, line_width = -1, filled = false):
	if filled :
		draw_circle(pos, radius, color);
	else:
		draw_arc(pos, radius, 0, PI * 2, 200, color, line_width, true);	

 所以,简单修改一下,就可以画出空心圆+实心点

	draw_rect(Rect2(0, 0, get_viewport_rect().size.x, get_viewport_rect().size.y), Color.BLACK)
	drawCircle(Vector2(300, 300), radius, lineColor);
	drawCircle(Vector2(450, 300), 2, Color.WHITE, -1, true);

2. 动点

点得动起来,才能看得出效果

从原理角度来说,动点是沿圆周逆时针转动,其与圆心连线有一个角度theta,该角度受时间t控制。当然,最精确的控制时间的地方在_physics_process函数中,可以定义一个全局角度变量deltaAngle = 0,在_physics_process中更新deltaAngle并强制刷新

func _physics_process(delta):
	deltaAngle -= 0.125 / PI;
	queue_redraw();

func _draw():	
	draw_rect(Rect2(0, 0, get_viewport_rect().size.x, get_viewport_rect().size.y), Color.BLACK)
	drawCircle(Vector2(300, 300), radius, lineColor);
	drawCircle(Vector2(300 + cos(deltaAngle) * 150, 300 + sin(deltaAngle) * 150), 2, Color.WHITE, -1, true);

现在就动起来了 

3. 分布规律

下来就是要看圆位置与动点角度的规律。这个过程就不分析了,反正我是简单分析后就直接提出规律,写代码测试验证即可。

为更好演示,加上级数控制

func _draw():	
	draw_rect(Rect2(0, 0, get_viewport_rect().size.x, get_viewport_rect().size.y), Color.BLACK)	
	drawCircleAtAngle(0, PI + deltaAngle);
	drawCircleAtAngle(PI, PI + deltaAngle - PI);
	
	var step = 2;
	while step <= pow(2, level):
		for i in step:
			drawCircleAtAngle(PI / step + i * 2 * PI / step, PI + deltaAngle - PI / step - i * 2 * PI / step);
		step *= 2;
	pass

然后就是最终效果

http://42.192.128.33:1880/hx.mp4

达到初步目标。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UE4/5动画系列(2.怎么套模板)

目录 大象套模板 动画同步&#xff08;这个在模板里面开同步&#xff09;&#xff1a; 速度限制&#xff1a; 穿墙问题&#xff1a; 在之前我们已经做了一个基础的模板了&#xff1a; UE4/5动画蓝图模板制作和套模板&#xff08;1.模板制作&#xff09;_多方通行8的博客-C…

【计算机组成原理】总线

目录 一、总线概述 二、总线的分类 三、系统总线的结构 四、总线的性能指标 五、总线仲裁 六、总线操作和定时 七、总线标准 一、总线概述 总线&#xff1a;是一组能为多个部件分时共享信息的传送线路 早期计算机外部设备少时大多采用分散连接方式&#xff0c;不易实现…

【C语言初阶】带你轻松玩转所有常用操作符(1)

君兮_的个人主页 勤时当勉励 岁月不待人 C/C 游戏开发 Hello,这里是君兮_&#xff0c;最近要准备期末复习了&#xff0c;可能更新的就不会那么频繁了&#xff0c;下个星期回复正常更新。 操作符详解1 前言一.操作符的分类二.算数操作符三.移位操作符1.二进制表示的三种形式2.…

【C/C++】构造函数与析构函数

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

【话题研究】重塑活力:顺应消费需求变化,PC市场需创新、技术驱动和营销策略更优解

话题研究&#xff1a;大众还需要PC吗&#xff1f;PC市场如何走出寒冬&#xff1f; 1️⃣ PC市场进入寒冬的深层原因2️⃣ PC仍具有独特的优势和不可替代性3️⃣ 创新、定制化和用户体验4️⃣ AI、VR时代带来的新出路 市场调研机构 Canalys数据显示&#xff0c;今年一季度&#…

elastic-job-ui在使用druid作为数据库连接池时作业维度报错

问题说明&#xff1a; 我们项目中使用到了elastic-job&#xff0c;然后自己封装了个sdk&#xff0c;方便使用&#xff0c;里面的数据源配置是常用的druidmysql的组合&#xff0c;在操作中&#xff0c;发现elastic-job-ui可视化控制台会报错无法使用。 深究其原因是因为&#…

返回值封装,异常统一处理优雅解决接口所有问题

在项目整体架构设计的时候&#xff0c;我们经常需要做以下工作&#xff1a; 返回值的统一封装处理&#xff0c;因为只有规范好统一的返回值格式&#xff0c;才能不会给接口使用者带来疑惑和方便前端对接口的统一处理。对异常码进行严格规定&#xff0c;什么错误返回什么码制&a…

ShardingSphere-JDBC 5.1.1 分库分表

分库分表解决的问题 mysql的扩展 mysql并不能完全利用高性能服务器的硬件&#xff0c;当cpu超过24个&#xff0c;内存超过128G时&#xff0c;mysql性能处于平缓&#xff0c;不在上升&#xff0c;所以在一个性能强大的服务器上运行多个实例&#xff0c;才更合理 mysql常见的扩…

java.sql.SQLException: No value specified for parameter 6

异常 java.sql.SQLException: No value specified for parameter 6 原因 sql中定义了6个参数&#xff0c;只传了5个参数

设计模式—“领域规则”

在特定领域中,某些变化虽然频繁,但可以抽象为某种规则。这时候,结合特定领域,将问题抽象为语法规则,从而给出在该领域下的一般性解决方案。 典型模式有:Interpreter Interpreter 动机 在软件构建过程中,如果某一个特定领域的问题比较复杂,类似的结构不断重复出现,…

.NET Microsoft.Extensions.Logging + NLog 记录日志到文件

最近想了解下面向对象开发&#xff0c;选择C# 语言 以及NET6.0 日志是开发中最常用的功能&#xff0c;本文记录下其中日志使用方法&#xff0c;理解不全的地方后续再学习补充 环境 Ubuntu 22.04.2 LTSdotnet 6.0.411 准备工作 # https://learn.microsoft.com/zh-cn/dotnet/c…

2023.6.21AgentGPT部署

在云服务器上使用Docker部署AgentGPT 需要自行提供OpenAI的API Key https://platform.openai.com/account/api-keys 需要自行提供云服务器或者虚拟机 需要自行解决网络的问题&#xff0c;本文中使用的是小喵咪解决网络的问题【需要订阅地址】 文章目录 在云服务器上使用Docker…

数据在内存中的存储-浮点型

常见的浮点型数据&#xff1a;单精度浮点型float、双精度浮点型double,还有long double类型。 浮点数表示的范围&#xff1a;float.h中定义 目录 一、浮点数存储的例子 二、浮点数存储规则 三、例题解释 一、浮点数存储的例子 #include<stdio.h> int main() {int …

王道操作系统学习笔记(1)——操作系统基本概念

前言 本文介绍了操作系统的基本概念&#xff0c;文章中的内容来自B站王道考研操作系统课程&#xff0c;想要完整学习的可以到B站官方看完整版。 一&#xff1a;操作系统基本概念 1.1.1&#xff1a;基本概念和功能 操作系统&#xff1a;系统资源的管理者&#xff08;处理机管…

QGIS 插件获取哨兵数据

基于 Sentinel Hub QGIS 插件&#xff0c;该插件允许您直接在 QGIS中配置和利用Sentinel Hub 服务的强大功能。该插件可视化 Sentinel 数据&#xff0c;可用于正在处理的任何其他项目中。 来自&#xff1a;GIS数据栈整理&#xff1a;GIS数据栈 一起来看看如何在QGIS中使用吧&am…

6张图表 + 1个案例 带你入门tcpdump的使用和原理

一、tcpdump简介 tcpdump是什么&#xff1f; 来看看 tcpdump官网怎么说&#xff1a;This is the home web site of tcpdump, a powerful command-line packet analyzer; and libpcap, a portable C/C library for network traffic capture. 不妨来看看chatGPT插件怎么说&…

【自我提升】openCV基本操作

写在前面&#xff1a;本篇博客主要是记录opnecv的基本操作&#xff0c;不记录安装等步骤。方便回顾和查找方法。 一、图像的IO操作&#xff0c;读取和保存方法 读取图像 在OpenCV中&#xff0c;读取图像的函数是imread()。该函数可以从指定的文件中加载图像&#xff0c;返回值…

Qt6.2教程——5.QT常用控件QLabel

1. QLabel简介 QLabel是Qt库中一个非常基础且重要的类。它主要用于在图形用户界面(GUI)中展示文本或图片。最常见的用法就是在窗口上显示一段文字或者标签&#xff0c;比如“用户名”&#xff0c;“密码”等等。QLabel继承自QFrame&#xff0c;因此它也可以具有框架。它能处理…

0005Java程序设计-jsp企业财务管理系统设计与实现

企业财务管理系统 摘要 对于企业集来说,财务管理的地位很重要。随着计算机和网络在企业中的广泛应用&#xff0c;企业发展速度在不断加快&#xff0c;在这种市场竞争冲击下企业财务管理系统必须优先发展&#xff0c;这样才能保证在竞争中处于优势地位。对此企业必须实现财务管…