今日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
当初の目標を達成します。