Godot 4 ソースコード分析 - 実践 - 調和のとれた共存

今日WeChatビデオを見ました、調和共生、おおよその効果は次のとおりです

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

長い間ゴドーを研究した後、上記の効果が今日達成できるかどうかを確認してください

一見すると、この効果はいくつかの手順で実現されます。

1. 円を描き、複数の円の位置の規則性を判断する

2. 移動点、および各移動点の移動法則を決定する

3. 包括的なデバッグ

1.円を描く

これは比較的単純なはずであり、直感的に描画できます。新しいプロジェクト描画を直接作成し、ルート シーンはCircleという名前のNode2Dで、スクリプトcircle.gdをバインドします。降りてきて、circle.gd に直接対処してください

学習と理解の観点からは、_draw() 関数を書き直して、draw_circle 関数を直接呼び出すようにする必要があります。

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

結果は出ましたが、難しくないようです。 

中空の円を描画する必要があるようですが、Godot のソース コードを見ると、draw_circle 関数のパラメータは中心点の座標、半径の長さ、色の 3 つだけです。

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,
	};

次に、1 つずつテストします。最初の 5 つはそれぞれ次の効果に対応します。

期待したような効果が感じられません。これらの列挙をもう一度見ると、OpenGL にも同様の定義があるのではないかと、少し親近感が湧きます。ゴドーは中空の円を描く方法を持っていませんか?

もちろんそうではありません。1 つの方法は、実線の円を描き、次に小さな半径で実線の円を描き、背景色を使用して、最後に中空の円のようにすることです。例えば

	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);

結果が得られると、まるで空洞になったような気分になります。

 

ただし、この方法は擬似的な中空円なので、部分的に重なる円を 2 つ描くと問題が発生します。

	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. 移動ポイント

動かして効果を確認してください

理論的な観点から見ると、移動点は円周に沿って反時計回りに回転し、移動点と円の中心の間には角度θがあり、これは時間 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

当初の目標を達成します。

おすすめ

転載: blog.csdn.net/drgraph/article/details/131366992