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