using Friflo.Engine.ECS;
using Microsoft.Xna.Framework;
using MrGameEng.Assets;
using MrGameEng.Core;
using MrGameEng.DevConsole;
using MrGameEng.Graphics;
using MrGameEng.Input;
using MrGameEng.UI;
namespace MrGameEng.Sample.Scenes;
///
/// Стресс-сцена: 100 000 спрайтов скачут в мире 4000×4000. Колесо — зум (чем дальше,
/// тем больше спрайтов в кадре), Tab — обратно в основную сцену. Цель: 60 FPS.
///
public sealed class StressScene : Scene
{
private const int SpriteCount = 100_000;
private static readonly RectF WorldBounds = new(-2000f, -2000f, 4000f, 4000f);
protected override void OnLoad()
{
var assets = Context.Services.Get();
var input = this.UseInput();
var actions = SampleInput.CreateActions(input);
var renderer = this.UseRenderer2D();
SampleLayers.EnsureRegistered(renderer);
var shapesTexture = assets.Load(GameAssets.Textures.Shapes);
var regions = new[]
{
new Texture2DRegion(shapesTexture, new Rectangle(0, 0, 32, 32)),
new Texture2DRegion(shapesTexture, new Rectangle(32, 0, 32, 32)),
new Texture2DRegion(shapesTexture, new Rectangle(0, 32, 32, 32)),
new Texture2DRegion(shapesTexture, new Rectangle(32, 32, 32, 32)),
};
var random = new Random(7);
for (var i = 0; i < SpriteCount; i++)
{
var sprite = new Sprite(regions[random.Next(regions.Length)]);
sprite.CenterOrigin();
var angle = random.NextSingle() * MathF.Tau;
Store.CreateEntity(
new Transform2D(
new Vector2(
random.NextSingle() * WorldBounds.Width + WorldBounds.Left,
random.NextSingle() * WorldBounds.Height + WorldBounds.Top),
scale: new Vector2(0.4f + random.NextSingle() * 0.6f)),
sprite,
new Velocity { Value = new Vector2(MathF.Cos(angle), MathF.Sin(angle)) * (30f + random.Next(150)) });
}
var camera = Store.CreateEntity(new Camera(Vector2.Zero, zoom: 0.3f));
var desktop = this.UseUI();
var statsLabel = new Myra.Graphics2D.UI.Label();
var backButton = new Myra.Graphics2D.UI.Button
{
Content = new Myra.Graphics2D.UI.Label { Text = "Back to main (Tab)" },
};
backButton.Click += (_, _) =>
{
if (!Context.Scenes.IsTransitioning)
{
Context.Scenes.Switch(new MainScene(), Transition.Wipe(0.8f, Color.DarkSlateBlue));
}
};
var panel = new Myra.Graphics2D.UI.VerticalStackPanel { Left = 12, Top = 12, Spacing = 6 };
panel.Widgets.Add(statsLabel);
panel.Widgets.Add(backButton);
desktop.Root = panel;
this.UseDevConsole(); // поверх UI
UpdateSystems.Add(new BounceSystem(WorldBounds));
UpdateSystems.Add(new StressCameraSystem(camera, input));
UpdateSystems.Add(new SceneHotkeysSystem(Context, actions, () => new MainScene(), Transition.Wipe(0.8f, Color.DarkSlateBlue)));
UpdateSystems.Add(new StatsSystem(Context, renderer, $"Stress {SpriteCount:N0}", statsLabel));
}
/// Только зум колесом — чтобы регулировать число видимых спрайтов.
private sealed class StressCameraSystem(Entity cameraEntity, InputManager input)
: Friflo.Engine.ECS.Systems.BaseSystem
{
protected override void OnUpdateGroup()
{
ref var camera = ref cameraEntity.GetComponent();
camera.Zoom = Math.Clamp(camera.Zoom * (1f + input.WheelDelta * 0.001f), 0.05f, 5f);
}
}
}