reckfellENGINE

Параллакс 2D: камера, слои и повтор фона

Два готовых слоя с разной глубиной, корректным периодом и запасом повторов при изменении окна.

На этой странице

Что получится

Два слоя повторяющегося фона движутся с разной скоростью относительно Camera2D. Белые точки находятся на дальнем слое, синие прямоугольники — на ближнем. Стрелки перемещают камеру. Рисунок создаётся кодом, поэтому внешние текстуры не нужны.

Это визуальный фон: повторение не создаёт копии Entity, физические тела или дополнительные уровни. Parallax2D подходит для слоёв декорации, а не для потоковой загрузки игрового мира.

Запустить полный пример

  1. Создайте C#-проект с Reckfell.NET.Sdk 1.0.0 и net10.0.
  2. Сохраните два файла ниже и выполните dotnet build.
  3. Создайте уровень с корнем Entity2D, прикрепите ParallaxExample.cs и сохраните parallax.rscene.
  4. Запустите этот уровень, дайте окну игры фокус и удерживайте стрелку вправо: узор синих прямоугольников уезжает влево быстрее белых точек.

Используются стандартные действия ui_left/ui_right/ui_up/ui_down. Если проект переназначил их, используются ваши назначения. Пример сам создаёт Camera2D и два слоя; не добавляйте второй комплект камеры или фона.

ParallaxPattern.cs
C#
using Reckfell;

public partial class ParallaxPattern : Entity2D
{
    public bool Distant { get; set; }

    public override void _Draw()
    {
        if (Distant)
        {
            DrawRect(new Rect2(0, 0, 128, 96), new Color(0.1f, 0.11f, 0.13f));
            DrawCircle(new Vector2(32, 24), 6, Colors.White);
            DrawCircle(new Vector2(96, 56), 3, Colors.White);
        }
        else
        {
            DrawRect(new Rect2(88, 64, 20, 32), new Color(0.25f, 0.45f, 1));
        }
    }
}
ParallaxExample.cs
C#
using Reckfell;

public partial class ParallaxExample : Entity2D
{
    public Parallax2D Far { get; private set; } = null!;
    public Parallax2D Near { get; private set; } = null!;
    public Camera2D Camera { get; private set; } = null!;
    private Vector2 _visibleSize;

    public override void _Ready()
    {
        Camera = new Camera2D { Position = GetViewportRect().Size * 0.5f };
        AddChild(Camera);
        Camera.MakeCurrent();
        Far = MakeLayer(0.25f, true, -20);
        Near = MakeLayer(0.75f, false, -10);
        FitRepeats();
    }

    private Parallax2D MakeLayer(float speed, bool distant, int order)
    {
        var layer = new Parallax2D
        {
            ScrollScale = new Vector2(speed, speed),
            RepeatSize = new Vector2(128, 96),
            ZIndex = order
        };
        layer.AddChild(new ParallaxPattern { Distant = distant });
        AddChild(layer);
        return layer;
    }

    public void FitRepeats()
    {
        Vector2 zoom = Camera.Zoom.Abs();
        if (zoom.X <= 0 || zoom.Y <= 0 || !zoom.IsFinite()) return;
        Vector2 visible = GetViewportRect().Size / zoom;
        if (visible == _visibleSize) return;
        _visibleSize = visible;
        int repeats = Mathf.CeilToInt(Mathf.Max(visible.X / 128, visible.Y / 96)) * 2 + 2;
        Far.RepeatTimes = repeats;
        Near.RepeatTimes = repeats;
    }

    public override void _Process(double delta)
    {
        Camera.Position += Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down") * 200 * (float)delta;
        FitRepeats();
    }
}

Выбрать скорость слоя

При стандартных FollowViewport=true, IgnoreCameraScroll=false, масштабе 1 и Zoom=(1,1) сдвиг камеры вправо на 40 единиц даёт такие смещения узора на экране:

ScrollScale.XСдвиг узора влевоПрименение
00Неподвижный относительно камеры дальний фон
0,2510Дальний слой примера
0,7530Ближний слой примера
140Скорость обычного мира

X и Y задаются отдельно. Меньшее значение обычно воспринимается как большая удалённость, но не меняет реальную геометрию или перспективу. При повторении координата слоя может скачком обернуться на период: одинаковый узор при этом сохраняется. Сравнивайте фазу и картинку, а не только сырое Position.

Настроить повтор без дыр

RepeatSize — период узора в локальных единицах, а не размер экрана. Наш рисунок занимает область (0,0)—(128,96), поэтому RepeatSize=(128,96). Ноль отключает повторение по соответствующей оси. Если нужны только горизонтальные повторы, задайте (128,0).

RepeatTimes определяет запас отрисовываемых повторов. Он не увеличивает размер рисунка и не создаёт дочерние Entity. FitRepeats пересчитывает запас под видимую область Viewport и положительную величину Camera.Zoom. При уменьшении Zoom видно больше мира, поэтому повторов требуется больше. Это простой консервативный расчёт для не повёрнутой камеры, масштаба слоёв 1 и данного периода; он не обещает минимальную стоимость отрисовки.

Если подставляете текстуру, поместите её начало в (0,0). Для Sprite2D с картинкой размером в один период обычно отключают Centered. Регионы атласа, смещение спрайта и масштаб дочернего рисунка должны согласовываться с периодом. Сам RepeatSize не обрезает изображение до прямоугольника и не делает несовпадающие края бесшовными.

Масштабирование картинки вдвое без изменения периода приводит к наложению соседних повторов. Слишком большой период оставляет промежуток. Для вертикально неповторяемой декорации отдельно обеспечьте покрытие по высоте: (128,0) не заполняет экран вверх и вниз автоматически.

Добавить движение без камеры

Задайте, например, Far.Autoscroll=(60,0): движок изменяет ScrollOffset со скоростью 60 локальных единиц в секунду. Это добавочное движение узора, а не скорость самой камеры. На повторяемой оси смещение оборачивается по RepeatSize.

Для встроенного Autoscroll хотя бы одна компонента RepeatSize должна быть ненулевой. При RepeatSize=(0,0) внутренняя обработка автопрокрутки выключается. ProcessMode=Disabled также останавливает её. В редакторе эта внутренняя автопрокрутка не выполняется как игровой процесс.

Меняйте ScrollOffset для ручного смещения фазы. Не записывайте Position каждый кадр: Parallax2D рассчитывает его сам. ScreenOffset по умолчанию обновляет камера; ручное управление им требует осознанной настройки IgnoreCameraScroll и FollowViewport. Для обычного фона оставьте оба параметра как в примере; для HUD используйте CanvasLayer.

Найти причину дефекта

СимптомПричина и действие
Не видно разницы глубиныПроверьте разные ScrollScale и активную Camera2D в том же Viewport
На широком окне или при zoom out появились пустотыУвеличьте RepeatTimes; не меняйте период только ради покрытия экрана
Видны швы или наложенияСогласуйте RepeatSize с фактическими размерами, смещением и краями рисунка
Autoscroll ничего не делаетПроверьте ненулевой RepeatSize, ProcessMode и запуск игры вместо ожидания движения в редакторе
Объект снова смещается после ручной установки PositionИспользуйте ScrollOffset; Position управляется реализацией параллакса
Копии декорации не сталкиваются с игрокомПовторы здесь только визуальные; игровую геометрию создавайте отдельно

Проверено в Compatibility/OpenGL: повтор рисунка по двум осям, смещения камеры 40 и 512 единиц, период ScrollOffset, автопрокрутка и её остановка, изменение Viewport и Zoom. Поворот камеры, неравномерный масштаб, LimitBegin/LimitEnd, другие рендереры и экспорт этим примером не проверены.

Координаты 2D · HUD отдельно от камеры · Движение персонажа

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.