reckfellENGINE

Custom 2D drawing: _Draw and QueueRedraw

Draw a marker, redraw when its data changes and apply the correct transform.

On this page

Complete example without textures

LocalMarker draws a circle and two lines in its own coordinates. Its center is Vector2.Zero; the entity's Position moves the result. DrawCircle does not create a physics body, clickable region or Control. Implement interaction separately.

Use Reckfell.NET.Sdk 1.0.0 and net10.0. Save LocalMarker.cs and CanvasExample.cs in your C# project, run dotnet build, create a level with an Entity2D root, attach CanvasExample.cs and save the .rscene. Run it: a white world marker and a blue HUD marker appear. The sample click handler moves the white marker.

LocalMarker.cs
C#
using Reckfell;

public partial class LocalMarker : Entity2D
{
    public float Radius { get; private set; } = 12;
    public Color Ink { get; private set; } = Colors.White;
    public int DrawCount { get; private set; }

    public bool SetStyle(float radius, Color ink)
    {
        if (!float.IsFinite(radius) || radius <= 0 || radius > 256)
            return false;
        Radius = radius;
        Ink = ink;
        QueueRedraw();
        return true;
    }

    public override void _Draw()
    {
        DrawCount++;
        DrawCircle(Vector2.Zero, Radius, Ink);
        DrawLine(new Vector2(-Radius, 0), new Vector2(Radius, 0), Colors.Black, 2);
        DrawLine(new Vector2(0, -Radius), new Vector2(0, Radius), Colors.Black, 2);
    }
}
CanvasExample.cs
C#
using Reckfell;

public partial class CanvasExample : Entity2D
{
    public Entity2D Rig { get; private set; } = null!;
    public LocalMarker Marker { get; private set; } = null!;
    public Camera2D Camera { get; private set; } = null!;
    public CanvasLayer Hud { get; private set; } = null!;
    public LocalMarker HudMarker { get; private set; } = null!;

    public override void _Ready()
    {
        Rig = new Entity2D { Position = new Vector2(64, 48) };
        AddChild(Rig);
        Marker = new LocalMarker { Position = new Vector2(24, 0) };
        Rig.AddChild(Marker);
        Camera = new Camera2D { Position = new Vector2(160, 120) };
        AddChild(Camera);
        Camera.MakeCurrent();
        Hud = new CanvasLayer { Layer = 1, FollowViewportEnabled = false };
        AddChild(Hud);
        HudMarker = new LocalMarker { Position = new Vector2(24, 24) };
        HudMarker.SetStyle(8, new Color(0.25f, 0.45f, 1));
        Hud.AddChild(HudMarker);
        var label = new Label { Position = new Vector2(42, 12), Text = "HUD" };
        Hud.AddChild(label);
    }

    public override void _UnhandledInput(InputEvent input)
    {
        if (input is InputEventMouseButton { Pressed: true, ButtonIndex: MouseButton.Left })
            Marker.Position = Rig.ToLocal(Rig.GetGlobalMousePosition());
    }
}

How drawing updates

The engine calls _Draw to record drawing commands. Call DrawCircle and DrawLine inside _Draw, not _Process. Recorded commands are reused on subsequent frames: _Draw is not a callback for every frame.

SetStyle validates the radius, updates data and calls QueueRedraw. This requests a deferred redraw rather than immediately calling _Draw. Requests made before processing are coalesced. DrawCount observes this callback; it does not measure GPU draw calls.

For an animated shape, update shape data in _Process using delta and request QueueRedraw. Changing only Position, Rotation or Scale transforms retained commands; the same circle does not need to be generated again.

Configure the shape

Radius uses local units. Parent scale changes the circle and line widths; nonuniform scale turns the circle into an ellipse. Keep a fixed-size HUD marker in an independent CanvasLayer with an appropriate scale.

Positive DrawLine width specifies thickness. Negative width selects a different line mode with different scaling behavior. The example explicitly uses 2. Antialiasing and thin-line sharpness depend on the drawing mode, coordinates and Viewport stretching; this sample does not configure project-wide AA.

Diagnose missing changes

  • Tried to assign Radius or Ink directly: these properties have private setters. Use SetStyle, which requests a redraw.
  • SetStyle returned false: radius must be finite and in (0,256]. This is a sample limit.
  • Called QueueRedraw outside the tree: the request is not kept in an unlimited queue. Adding a visible CanvasItem schedules its initial drawing.
  • Expected changed pixels immediately: wait for a frame. Callback execution, submission and presentation are different stages.
  • Called QueueRedraw from _Draw: move state changes outside the callback instead of building a redraw loop inside it.

Coordinates · Layers

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.