spikes/KniWeb (outside LittleSim.sln): a kni-blazor-gl template project (KNI 4.2.9001, net8.0) referencing MrGameEng.Core directly. A mini-host in the GameHost mold drives EngineContext/GameClock/Scene phases over KNI's Game; the scene moves 300 Friflo entities in the update phase and draws them with SpriteBatch (WebGL). Verified in a real browser: sprites render and animate, browser console is clean. Decision (docs/web-client.md): path A — KNI — is the primary route for the web client; the core runs in Blazor WASM unchanged thanks to the Core/Host split. Known follow-ups: per-platform compilation of the graphics libraries against nkast.* packages, shader compatibility for Renderer2D, HTTP-served content instead of the filesystem. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
149 lines
4.8 KiB
C#
149 lines
4.8 KiB
C#
using System;
|
|
using Friflo.Engine.ECS;
|
|
using Friflo.Engine.ECS.Systems;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using MrGameEng.Core;
|
|
|
|
namespace KniWebSpike
|
|
{
|
|
// Компоненты симуляции — платформо-независимые, как в LittleSim.
|
|
public struct DotPosition : IComponent
|
|
{
|
|
public float X;
|
|
public float Y;
|
|
}
|
|
|
|
public struct DotVelocity : IComponent
|
|
{
|
|
public float X;
|
|
public float Y;
|
|
}
|
|
|
|
public struct DotTint : IComponent
|
|
{
|
|
public byte R;
|
|
public byte G;
|
|
public byte B;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Сцена спайка: 300 «спрайтов» в Friflo EntityStore, движение в Update-фазе
|
|
/// (детерминированный seed, отскок от краёв), отрисовка в Draw-фазе через
|
|
/// KNI SpriteBatch (WebGL). Сцена и системные корни — из MrGameEng.Core.
|
|
/// </summary>
|
|
public sealed class SpikeScene : Scene
|
|
{
|
|
private readonly Func<SpriteBatch> _spriteBatch;
|
|
private readonly Func<Texture2D> _pixel;
|
|
private readonly float _width;
|
|
private readonly float _height;
|
|
|
|
public SpikeScene(Func<SpriteBatch> spriteBatch, Func<Texture2D> pixel, float width, float height)
|
|
{
|
|
_spriteBatch = spriteBatch;
|
|
_pixel = pixel;
|
|
_width = width;
|
|
_height = height;
|
|
}
|
|
|
|
protected override void OnLoad()
|
|
{
|
|
var random = new Random(42);
|
|
for (var i = 0; i < 300; i++)
|
|
{
|
|
var angle = (float)(random.NextDouble() * Math.Tau);
|
|
var speed = 40f + (float)random.NextDouble() * 160f;
|
|
Store.CreateEntity(
|
|
new DotPosition
|
|
{
|
|
X = (float)random.NextDouble() * _width,
|
|
Y = (float)random.NextDouble() * _height,
|
|
},
|
|
new DotVelocity
|
|
{
|
|
X = MathF.Cos(angle) * speed,
|
|
Y = MathF.Sin(angle) * speed,
|
|
},
|
|
new DotTint
|
|
{
|
|
R = (byte)random.Next(64, 256),
|
|
G = (byte)random.Next(64, 256),
|
|
B = (byte)random.Next(64, 256),
|
|
}
|
|
);
|
|
}
|
|
|
|
UpdateSystems.Add(new BounceSystem(_width, _height));
|
|
DrawSystems.Add(new DotDrawSystem(_spriteBatch, _pixel));
|
|
}
|
|
|
|
private sealed class BounceSystem : QuerySystem<DotPosition, DotVelocity>
|
|
{
|
|
private readonly float _width;
|
|
private readonly float _height;
|
|
|
|
public BounceSystem(float width, float height)
|
|
{
|
|
_width = width;
|
|
_height = height;
|
|
}
|
|
|
|
protected override void OnUpdate()
|
|
{
|
|
var delta = Tick.deltaTime;
|
|
var width = _width;
|
|
var height = _height;
|
|
Query.ForEachEntity(
|
|
(ref DotPosition pos, ref DotVelocity vel, Entity _) =>
|
|
{
|
|
pos.X += vel.X * delta;
|
|
pos.Y += vel.Y * delta;
|
|
if (pos.X < 0f || pos.X > width)
|
|
{
|
|
vel.X = -vel.X;
|
|
pos.X = Math.Clamp(pos.X, 0f, width);
|
|
}
|
|
|
|
if (pos.Y < 0f || pos.Y > height)
|
|
{
|
|
vel.Y = -vel.Y;
|
|
pos.Y = Math.Clamp(pos.Y, 0f, height);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
private sealed class DotDrawSystem : QuerySystem<DotPosition, DotTint>
|
|
{
|
|
private readonly Func<SpriteBatch> _spriteBatch;
|
|
private readonly Func<Texture2D> _pixel;
|
|
|
|
public DotDrawSystem(Func<SpriteBatch> spriteBatch, Func<Texture2D> pixel)
|
|
{
|
|
_spriteBatch = spriteBatch;
|
|
_pixel = pixel;
|
|
}
|
|
|
|
protected override void OnUpdate()
|
|
{
|
|
var batch = _spriteBatch();
|
|
var pixel = _pixel();
|
|
batch.Begin();
|
|
Query.ForEachEntity(
|
|
(ref DotPosition pos, ref DotTint tint, Entity _) =>
|
|
{
|
|
batch.Draw(
|
|
pixel,
|
|
new Rectangle((int)pos.X, (int)pos.Y, 6, 6),
|
|
new Color(tint.R, tint.G, tint.B)
|
|
);
|
|
}
|
|
);
|
|
batch.End();
|
|
}
|
|
}
|
|
}
|
|
}
|