using Friflo.Engine.ECS; using Microsoft.Xna.Framework; using MrGameEng.Assets; using MrGameEng.Audio; using MrGameEng.Core; using MrGameEng.Graphics; using MrGameEng.Input; namespace MrGameEng.Sample.Scenes; /// /// Интерактивная демо-сцена: ассеты через сгенерированные хендлы, анимация, слои /// (мир + Y-sort + screen-space HUD), камера с зумом/поворотом, ввод, звук и музыка. /// WASD — игрок, колесо — зум, Q/E — поворот, Space — звук, P — пауза, M — музыка, Tab — стресс-сцена. /// public sealed class MainScene : Scene { private const int DecorCount = 1500; private static readonly RectF WorldBounds = new(-2000f, -2000f, 4000f, 4000f); protected override void OnLoad() { var assets = Context.Services.GetOrDefault() ?? Context.UseAssets(); var audio = Context.Services.GetOrDefault() ?? Context.UseAudio(); var input = this.UseInput(); var actions = SampleInput.CreateActions(input); this.UseSpriteAnimation(); var renderer = this.UseRenderer2D(new Renderer2DOptions { VirtualResolution = new Point(1280, 720) }); SampleLayers.EnsureRegistered(renderer); var playerTexture = assets.Load(GameAssets.Textures.Player); var shapesTexture = assets.Load(GameAssets.Textures.Shapes); var beep = assets.Load(GameAssets.Sounds.Beep); var shapeRegions = 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)), }; // Декорации по всему миру: уезжаешь камерой — попадают под culling (см. заголовок окна). var random = new Random(42); for (var i = 0; i < DecorCount; i++) { var sprite = new Sprite(shapeRegions[random.Next(shapeRegions.Length)]); sprite.CenterOrigin(); sprite.Color = Color.White * 0.35f; Store.CreateEntity( new Transform2D( new Vector2( random.NextSingle() * WorldBounds.Width + WorldBounds.Left, random.NextSingle() * WorldBounds.Height + WorldBounds.Top), rotation: random.NextSingle() * MathF.Tau, scale: new Vector2(0.5f + random.NextSingle())), sprite); } // Бродячие "существа" на Y-sort слое: кто ниже на экране — тот ближе. for (var i = 0; i < 200; i++) { var sprite = new Sprite(shapeRegions[random.Next(shapeRegions.Length)], SampleLayers.Actors); sprite.CenterOrigin(); var angle = random.NextSingle() * MathF.Tau; Store.CreateEntity( new Transform2D(new Vector2(random.Next(-600, 600), random.Next(-400, 400))), sprite, new Velocity { Value = new Vector2(MathF.Cos(angle), MathF.Sin(angle)) * (40f + random.Next(80)) }); } // Игрок: анимированный спрайт (2 кадра из атласа player.png), Y-sort слой. var playerSprite = new Sprite(new Texture2DRegion(playerTexture, new Rectangle(0, 0, 32, 32)), SampleLayers.Actors); playerSprite.CenterOrigin(); var blink = new SpriteAnimationClip( [ new Texture2DRegion(playerTexture, new Rectangle(0, 0, 32, 32)), new Texture2DRegion(playerTexture, new Rectangle(32, 0, 32, 32)), ], framesPerSecond: 3f); var player = Store.CreateEntity( new Transform2D(Vector2.Zero, scale: new Vector2(2f)), playerSprite, new SpriteAnimator(blink)); var camera = Store.CreateEntity(new Camera(Vector2.Zero, zoom: 1f, bounds: WorldBounds)); // HUD: золотой квадрат в углу на screen-space слое — не двигается с камерой. var hud = new Sprite(shapeRegions[3], SampleLayers.Ui); Store.CreateEntity(new Transform2D(new Vector2(16f, 16f)), hud); UpdateSystems.Add(new PlayerControlSystem(player, actions, audio, beep)); UpdateSystems.Add(new BounceSystem(WorldBounds)); UpdateSystems.Add(new CameraControlSystem(camera, player, input)); UpdateSystems.Add(new SceneHotkeysSystem(Context, actions, () => new StressScene(), Transition.Fade(0.8f))); UpdateSystems.Add(new TitleStatsSystem(Context, renderer, "Main")); var music = audio.Music; if (!music.IsPlaying) { music.Volume = 0.4f; music.Play(assets.Load(GameAssets.Music.Theme)); } } }