From a217b50fd366cab6cce161d7daabe3621ec70c2b Mon Sep 17 00:00:00 2001 From: Selinux24 Date: Mon, 5 Aug 2024 17:33:59 +0200 Subject: [PATCH] Added more cars and best car testing in the virtual world scene --- Engine/Common/EngineShaderStageState.cs | 5 + .../Common/Agents/AgentFollower.cs | 10 +- Samples/05 AISamples/Common/Agents/Car.cs | 14 ++- Samples/05 AISamples/Common/World.cs | 27 ++--- .../SelfDrivingCarScene.cs | 35 ++++--- .../SceneCWRVirtualWorld/VirtualWorldScene.cs | 98 ++++++++++++++++--- 6 files changed, 143 insertions(+), 46 deletions(-) diff --git a/Engine/Common/EngineShaderStageState.cs b/Engine/Common/EngineShaderStageState.cs index 1ec082b8..0986f1c8 100644 --- a/Engine/Common/EngineShaderStageState.cs +++ b/Engine/Common/EngineShaderStageState.cs @@ -28,6 +28,11 @@ public class EngineShaderStageState(EngineDeviceContext deviceContext) /// public IEnumerable GetResources() { + if(resources.Count == 0) + { + return []; + } + int maxSlot = resources.Keys.Max(); T[] values = new T[maxSlot + 1]; diff --git a/Samples/05 AISamples/Common/Agents/AgentFollower.cs b/Samples/05 AISamples/Common/Agents/AgentFollower.cs index e091781b..84f43dbd 100644 --- a/Samples/05 AISamples/Common/Agents/AgentFollower.cs +++ b/Samples/05 AISamples/Common/Agents/AgentFollower.cs @@ -1,5 +1,6 @@ using Engine; using SharpDX; +using System; namespace AISamples.Common.Agents { @@ -8,20 +9,21 @@ class AgentFollower(float distance, float height) : IFollower private readonly float distance = distance; private readonly float height = height; - public Car Car { get; set; } + public Func Car { get; set; } public Vector3 Position { get; private set; } public Vector3 Interest { get; private set; } public float Velocity { get; set; } public void Update(IGameTime gameTime) { - if (Car == null) + var car = Car?.Invoke(); + if (car == null) { return; } - var p = Car.GetPosition(); - var d = -Car.GetDirection(); + var p = car.GetPosition(); + var d = -car.GetDirection(); var d3 = new Vector3(d.X, 0f, d.Y) * distance; d3.Y = height; diff --git a/Samples/05 AISamples/Common/Agents/Car.cs b/Samples/05 AISamples/Common/Agents/Car.cs index e62cb34f..d000cb96 100644 --- a/Samples/05 AISamples/Common/Agents/Car.cs +++ b/Samples/05 AISamples/Common/Agents/Car.cs @@ -36,6 +36,7 @@ class Car public Sensor Sensor { get; } public NeuralNetwork Brain { get; } public bool Damaged { get; private set; } = false; + public float FittnessValue { get; set; } = 0; public Car(float width, float height, float depth, AgentControlTypes controlType, float maxSpeed = 3f, float maxReverseSpeed = 1.5f) { @@ -143,9 +144,10 @@ private void Move(float time) angle += rot * MathF.Sign(speed); } - direction = new Vector2(MathF.Sin(angle), MathF.Cos(angle)); - x += direction.X * speed; - y += direction.Y * speed; + direction = new Vector2(MathF.Sin(angle), MathF.Cos(angle)) * speed; + x += direction.X; + y += direction.Y; + FittnessValue += direction.LengthSquared(); } private bool AssessDamage(Segment2[] roadBorders, Car[] traffic, bool damageTraffic) { @@ -219,9 +221,11 @@ public OrientedBoundingBox GetBox() { return trnBox; } - public Matrix GetTransform() + public Matrix GetTransform(float height = 0) { - return Matrix.Scaling(scale) * trnBox.Transformation; + var trn = Matrix.RotationY(angle) * Matrix.Translation(x, height, y); + + return Matrix.Scaling(scale) * trn; } } } diff --git a/Samples/05 AISamples/Common/World.cs b/Samples/05 AISamples/Common/World.cs index 0800e654..1f4a8d6f 100644 --- a/Samples/05 AISamples/Common/World.cs +++ b/Samples/05 AISamples/Common/World.cs @@ -57,8 +57,10 @@ class World(Graph graph, float height) private GeometryDrawer markingsDrawer2d = null; private GeometryDrawer markingsDrawer3d = null; - private Car bestCar = null; private readonly List cars = []; + private Car bestCar = null; + private readonly Color4 bestCarColor = new Color(252, 212, 32, 255); + private readonly Color4 carColor = new Color(252, 222, 200, 255); public Graph Graph { get => graph; } public Guid Version { get; private set; } = Guid.NewGuid(); @@ -432,7 +434,7 @@ private void UpdateCars(IGameTime gameTime, ModelInstanced carDrawer) for (int i = 0; i < maxCarCount; i++) { - if (i >= cars.Count) + if (i >= cars.Count || cars[i].Damaged) { carDrawer[i].Manipulator.SetTransform(Matrix.Translation(Vector3.One * 10000000f)); carDrawer[i].TintColor = Color.Black; @@ -444,9 +446,11 @@ private void UpdateCars(IGameTime gameTime, ModelInstanced carDrawer) car.Update(gameTime, road, [], false); - carDrawer[i].Manipulator.SetTransform(car.GetTransform()); - carDrawer[i].TintColor = car == bestCar ? Color.Yellow : Color.White; + carDrawer[i].Manipulator.SetTransform(car.GetTransform(height + hLayer)); + carDrawer[i].TintColor = car == bestCar ? bestCarColor : carColor; } + + bestCar = cars.MaxBy(c => c.FittnessValue); } private void DrawMarkings() { @@ -592,18 +596,13 @@ public void RemoveMarking(Marking marking) return (fStart.Position, fStart.Direction); } - public void AddCar(Car car, bool isBestCar = false) + public void AddCar(Car car) { if (cars.Contains(car)) { return; } - if (isBestCar) - { - bestCar = car; - } - cars.Add(car); } public void RemoveCar(Car car) @@ -626,10 +625,16 @@ public void Clear() laneGuides.Clear(); markings.Clear(); - cars.Clear(); + ClearTraffic(); worldChanged = true; Version = Guid.NewGuid(); } + public void ClearTraffic() + { + cars.Clear(); + + bestCar = null; + } } } diff --git a/Samples/05 AISamples/SceneCWRSelfDrivingCar/SelfDrivingCarScene.cs b/Samples/05 AISamples/SceneCWRSelfDrivingCar/SelfDrivingCarScene.cs index 8f16782a..5905c107 100644 --- a/Samples/05 AISamples/SceneCWRSelfDrivingCar/SelfDrivingCarScene.cs +++ b/Samples/05 AISamples/SceneCWRSelfDrivingCar/SelfDrivingCarScene.cs @@ -42,6 +42,7 @@ class SelfDrivingCarScene : Scene private GeometryColorDrawer roadDrawer = null; private GeometryColorDrawer roadLaneDrawer = null; private Model terrain = null; + private float carScale = 1f; private ModelInstanced carModels = null; private ModelInstanced trafficModels = null; @@ -91,6 +92,8 @@ public SelfDrivingCarScene(Game game) : base(game) Game.LockMouse = false; GameEnvironment.Background = Color.Black; + + Lights.SetAmbient(new SceneLightHemispheric("Ambient", Color3.White, Color3.Black, true)); } public override void Initialize() @@ -238,29 +241,34 @@ private async Task InitializeVisualizerDrawer() } private async Task InitializeCars() { - var geo = GeometryUtil.CreateBox(Topology.TriangleList, carWidth, carHeight, carLength); - var mat = MaterialPhongContent.Default; - mat.IsTransparent = true; - var cDesc = new ModelInstancedDescription() { Instances = maxCarInstances, CastShadow = ShadowCastingAlgorihtms.All, - Content = ContentDescription.FromContentData(ContentData.GenerateTriangleList(geo, mat)), - BlendMode = BlendModes.Alpha, + Content = ContentDescription.FromFile(Constants.TrafficResourcesFolder, Constants.TaxiModel), + BlendMode = BlendModes.OpaqueAlpha, StartsVisible = false, }; - carModels = await AddComponentAgent("Cars", "Cars", cDesc); + carModels = await AddComponentAgent( + nameof(carModels), + nameof(carModels), + cDesc); var tDesc = new ModelInstancedDescription() { Instances = maxTrafficInstances, CastShadow = ShadowCastingAlgorihtms.All, - Content = ContentDescription.FromContentData(ContentData.GenerateTriangleList(geo, mat)), - BlendMode = BlendModes.Alpha, + Content = ContentDescription.FromFile(Constants.TrafficResourcesFolder, Constants.TaxiModel), + BlendMode = BlendModes.OpaqueAlpha, StartsVisible = false, }; - trafficModels = await AddComponentAgent("Traffic", "Traffic", tDesc); + trafficModels = await AddComponentAgent( + nameof(trafficModels), + nameof(trafficModels), + tDesc); + + var bbox = carModels[0].GetBoundingBox(); + carScale = MathF.Max(MathF.Max(carWidth / bbox.Width, carHeight / bbox.Height), carLength / bbox.Depth); cars = new Car[maxCarInstances]; traffic = new Car[maxTrafficInstances]; @@ -618,7 +626,7 @@ private void SelectBestCar() if (c != null) { bestCar = c; - carFollower.Car = bestCar; + carFollower.Car = () => bestCar; } } @@ -652,6 +660,7 @@ private void StartSimulation() for (int i = 0; i < cars.Length; i++) { cars[i] = new(carWidth, carHeight, carLength, AgentControlTypes.AI, 1, 0.5f); + cars[i].SetScale(carScale); if (!mutate) { @@ -666,11 +675,13 @@ private void StartSimulation() cars[i].Brain.Mutate(0.1f); } - carFollower.Car = bestCar = cars[0]; + bestCar = cars[0]; + carFollower.Car = () => bestCar; for (int i = 0; i < traffic.Length; i++) { traffic[i] = new(carWidth, carHeight, carLength, AgentControlTypes.Dummy, 0.5f, 0.25f); + traffic[i].SetScale(carScale); var lanePos = road.GetLaneCenter(i % traffic.Length); lanePos.Y = Helper.RandomGenerator.NextFloat(0, 3) * -(carLength * 3); diff --git a/Samples/05 AISamples/SceneCWRVirtualWorld/VirtualWorldScene.cs b/Samples/05 AISamples/SceneCWRVirtualWorld/VirtualWorldScene.cs index de0de1dc..7c13be79 100644 --- a/Samples/05 AISamples/SceneCWRVirtualWorld/VirtualWorldScene.cs +++ b/Samples/05 AISamples/SceneCWRVirtualWorld/VirtualWorldScene.cs @@ -57,6 +57,7 @@ class VirtualWorldScene : Scene SPACE - MOVE CAMERA UP C - MOVE CAMERA DOWN MOUSE - ROTATE CAMERA +F - TOGGLE CAR FOLLOWING ESC - EXIT"; private bool showHelp = false; @@ -71,11 +72,16 @@ class VirtualWorldScene : Scene private const float carWidth = 8; private const float carHeight = 6; private const float carLength = 15; - private const int maxCarInstances = 10; - private readonly Car bestCar = new(carWidth, carHeight, carLength, AgentControlTypes.Player, 1, 0.2f); + private const float carMaxSpeed = 1f; + private const float carMaxReverseSpeed = 0.2f; + private const int maxCarInstances = 100; + private const float carMutationDelta = 0.2f; private float carScale = 1f; private ModelInstanced carDrawer = null; + private bool followCar = false; + private readonly AgentFollower carFollower = new(100, 50); + public VirtualWorldScene(Game game) : base(game) { Game.VisibleMouse = true; @@ -237,7 +243,6 @@ private async Task InitializeCar() cDesc); var bbox = carDrawer[0].GetBoundingBox(); - carScale = MathF.Max(MathF.Max(carWidth / bbox.Width, carHeight / bbox.Height), carLength / bbox.Depth); } private void InitializeComponentsCompleted(LoadResourcesResult res) @@ -292,10 +297,7 @@ public override void Update(IGameTime gameTime) ToggleTools(); } - if (Game.Input.KeyJustReleased(Keys.F5)) - { - ResetCars(); - } + UpdateInputCars(); UpdateInputCamera(gameTime); @@ -317,6 +319,22 @@ private void ToggleHelp() } } private void UpdateInputCamera(IGameTime gameTime) + { + if (!followCar) + { + Camera.Following = null; + + UpdateInputCameraManual(gameTime); + + return; + } + + if (Camera.Following == null) + { + Camera.Following = carFollower; + } + } + private void UpdateInputCameraManual(IGameTime gameTime) { if (Game.Input.MouseButtonPressed(MouseButtons.Right)) { @@ -402,23 +420,75 @@ private void UpdateTools(IGameTime gameTime) tools.Draw(); } - private void ResetCars() + private void UpdateInputCars() + { + if (Game.Input.KeyJustReleased(Keys.F5)) + { + AddCar(false); + } + if (Game.Input.KeyJustReleased(Keys.F6)) + { + AddCar(true); + } + if (Game.Input.KeyJustReleased(Keys.F7)) + { + AddCars(maxCarInstances); + } + if (Game.Input.KeyJustReleased(Keys.F8)) + { + SaveBestCar(); + } + if (Game.Input.KeyJustReleased(Keys.F)) + { + ToggleFollow(); + } + } + private void AddCars(int count) + { + world.ClearTraffic(); + + for (int i = 0; i < count; i++) + { + AddCar(i != 0); + } + } + private void AddCar(bool mutate) { if (!world.Populated) { return; } - bestCar.Reset(); - bestCar.Brain.Load(bestCarFileName); + var car = new Car(carWidth, carHeight, carLength, AgentControlTypes.AI, carMaxSpeed, carMaxReverseSpeed); + car.Brain.Load(bestCarFileName); + if (mutate) + { + car.Brain.Mutate(carMutationDelta); + } (Vector2 start, Vector2 dir) = world.GetStart(); - bestCar.SetPosition(start); - bestCar.SetDirection(dir); + car.SetPosition(start); + car.SetDirection(dir); + + car.SetScale(carScale); - bestCar.SetScale(carScale); + world.AddCar(car); + + carFollower.Car = world.GetBestCar; + } + private void ToggleFollow() + { + followCar = !followCar; + } + private void SaveBestCar() + { + var bestCar = world.GetBestCar(); + if (bestCar == null) + { + return; + } - world.AddCar(bestCar, true); + bestCar.Brain.Save(bestCarFileName); } public override void GameGraphicsResized()