diff --git a/DoomDeathmatch/src/Component/ConsumableComponent.cs b/DoomDeathmatch/src/Component/ConsumableComponent.cs index 867abf2..a8bf358 100644 --- a/DoomDeathmatch/src/Component/ConsumableComponent.cs +++ b/DoomDeathmatch/src/Component/ConsumableComponent.cs @@ -36,7 +36,7 @@ public class ConsumableComponent : Engine.Scene.Component.Component /// /// Controls the movement of the consumable object. /// - private MovementController _movementController = null!; + private MovementComponent _movementComponent = null!; /// /// Initializes a new instance of the class. @@ -57,9 +57,9 @@ public class ConsumableComponent : Engine.Scene.Component.Component _collider.OnCollision += OnCollision; _box2DRenderer.Texture = EngineUtil.AssetResourceManager.Load(_consumable.Icon); - _movementController = GameObject.GetComponent()!; + _movementComponent = GameObject.GetComponent()!; - ArgumentNullException.ThrowIfNull(_movementController); + ArgumentNullException.ThrowIfNull(_movementComponent); } /// @@ -113,7 +113,7 @@ public class ConsumableComponent : Engine.Scene.Component.Component direction.Normalize(); } - _movementController.ApplyMovement(direction); + _movementComponent.ApplyMovement(direction); } /// diff --git a/DoomDeathmatch/src/Component/MVC/Enemy/EnemyController.cs b/DoomDeathmatch/src/Component/MVC/Enemy/EnemyController.cs index 93d459c..0275391 100644 --- a/DoomDeathmatch/src/Component/MVC/Enemy/EnemyController.cs +++ b/DoomDeathmatch/src/Component/MVC/Enemy/EnemyController.cs @@ -30,7 +30,7 @@ public class EnemyController : Engine.Scene.Component.Component /// /// Controls the movement of the enemy. /// - private MovementController _movementController = null!; + private MovementComponent _movementComponent = null!; /// /// Handles the enemy's attack behavior. @@ -56,19 +56,19 @@ public class EnemyController : Engine.Scene.Component.Component _gameController = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent()!; HealthController = GameObject.GetComponent()!; _enemyView = GameObject.GetComponent>()!; - _movementController = GameObject.GetComponent()!; + _movementComponent = GameObject.GetComponent()!; ArgumentNullException.ThrowIfNull(_gameController); ArgumentNullException.ThrowIfNull(HealthController); ArgumentNullException.ThrowIfNull(_enemyView); - ArgumentNullException.ThrowIfNull(_movementController); + ArgumentNullException.ThrowIfNull(_movementComponent); _attackBehavior = _enemyData.AttackBehaviorCreator.Create(this, _gameController.PlayerController.HealthController); HealthController.SetMaxHealth(_enemyData.BaseHealth); HealthController.OnDeath += OnDeath; _enemyView.UpdateView(_enemyData); - _movementController.Speed = _enemyData.BaseSpeed; + _movementComponent.Speed = _enemyData.BaseSpeed; } public override void Start() @@ -92,7 +92,7 @@ public class EnemyController : Engine.Scene.Component.Component if (enemyPosition != nextPosition) { var direction = (nextPosition - enemyPosition).Normalized(); - _movementController.ApplyMovement(direction); + _movementComponent.ApplyMovement(direction); } _attackBehavior.Attack(parDeltaTime); diff --git a/DoomDeathmatch/src/Component/MVC/MovementController.cs b/DoomDeathmatch/src/Component/MVC/MovementComponent.cs similarity index 94% rename from DoomDeathmatch/src/Component/MVC/MovementController.cs rename to DoomDeathmatch/src/Component/MVC/MovementComponent.cs index 2ee7ac5..60484f4 100644 --- a/DoomDeathmatch/src/Component/MVC/MovementController.cs +++ b/DoomDeathmatch/src/Component/MVC/MovementComponent.cs @@ -6,7 +6,7 @@ namespace DoomDeathmatch.Component.MVC; /// /// Controls the movement logic for a game object, applying movement forces to the rigidbody. /// -public class MovementController : Engine.Scene.Component.Component +public class MovementComponent : Engine.Scene.Component.Component { /// /// The movement speed. diff --git a/DoomDeathmatch/src/Component/MVC/PlayerController.cs b/DoomDeathmatch/src/Component/MVC/PlayerController.cs index b4af6b1..6019941 100644 --- a/DoomDeathmatch/src/Component/MVC/PlayerController.cs +++ b/DoomDeathmatch/src/Component/MVC/PlayerController.cs @@ -1,7 +1,6 @@ using DoomDeathmatch.Component.MVC.Enemy; using DoomDeathmatch.Component.MVC.Health; using DoomDeathmatch.Component.MVC.Weapon; -using DoomDeathmatch.Component.Physics.Collision; using Engine.Input; using Engine.Scene.Component.BuiltIn; using Engine.Util; @@ -71,6 +70,34 @@ public class PlayerController : Engine.Scene.Component.Component return; } + ExecuteWeaponSelection(); + + ExecuteWeaponShooting(); + } + + /// + /// Handles weapon shooting. + /// + private void ExecuteWeaponShooting() + { + if (!_inputHandler.IsKeyJustPressed(KeyboardButtonCode.Space)) + { + return; + } + + if (!WeaponController.TryShoot()) + { + return; + } + + ShootSelectedWeapon(); + } + + /// + /// Handles weapon selection. + /// + private void ExecuteWeaponSelection() + { for (var i = 0; i < 10; i++) { if (KeyboardButtonCode.D1 + i > KeyboardButtonCode.D0) @@ -86,38 +113,20 @@ public class PlayerController : Engine.Scene.Component.Component WeaponController.SelectWeapon(i); break; } - - if (_inputHandler.IsKeyJustPressed(KeyboardButtonCode.Space)) - { - if (!WeaponController.TryShoot()) - { - return; - } - - HandleShootingRaycast(); - } } /// - /// Handles the shooting raycast for the player. + /// Shoots the selected weapon. /// - private void HandleShootingRaycast() + private void ShootSelectedWeapon() { var position = Camera.GameObject.Transform.GetFullTranslation(); var forward = (Camera.Forward - position).Normalized(); - var right = Vector3.Cross(forward, Vector3.UnitZ).Normalized(); + var up = Vector3.UnitZ; + var groups = new HashSet { "enemy", "wall" }; - var collisionManager = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent(); - - var offsets = WeaponController.WeaponData.ShootPattern.GetShootPattern(forward, Vector3.UnitZ, right); - foreach (var offset in offsets) + foreach (var result in WeaponController.RaycastWeaponShooting(position, forward, up, groups)) { - var direction = forward + offset; - if (!collisionManager!.Raycast(position, direction, ["enemy", "wall"], out var result)) - { - continue; - } - var enemyController = result.HitObject.GetComponent(); enemyController?.HealthController.TakeDamage(WeaponController.WeaponData.Damage); } diff --git a/DoomDeathmatch/src/Component/MVC/Weapon/WeaponController.cs b/DoomDeathmatch/src/Component/MVC/Weapon/WeaponController.cs index b50f0b8..090d5e3 100644 --- a/DoomDeathmatch/src/Component/MVC/Weapon/WeaponController.cs +++ b/DoomDeathmatch/src/Component/MVC/Weapon/WeaponController.cs @@ -1,5 +1,9 @@ -using DoomDeathmatch.Script.Model; +using DoomDeathmatch.Component.Physics.Collision; +using DoomDeathmatch.Script.Collision; +using DoomDeathmatch.Script.Model; using DoomDeathmatch.Script.Model.Weapon; +using Engine.Util; +using OpenTK.Mathematics; namespace DoomDeathmatch.Component.MVC.Weapon; @@ -21,21 +25,25 @@ public class WeaponController : Engine.Scene.Component.Component /// /// The internal weapon model containing weapon-related data. /// - private readonly WeaponModel _weaponModel = new(); + private readonly WeaponModel _weaponModel; /// /// View responsible for displaying weapon information and animations. /// private IWeaponView _weaponView = null!; + /// + /// Initializes a new instance of the class with an initial weapon. + /// + /// The initial weapon. + public WeaponController(WeaponData parInitialWeapon) + { + _weaponModel = new WeaponModel(parInitialWeapon); + } + public override void Awake() { _weaponView = GameObject.GetComponent()!; - _weaponView.UpdateView(_weaponModel.SelectedWeapon); - _weaponView.UpdateView(new AmmoData - { - Ammo = _weaponModel.SelectedWeapon.Ammo, MaxAmmo = _weaponModel.SelectedWeapon.MaxAmmo - }); _weaponModel.OnWeaponSelected += WeaponSelected; WeaponSelected(null, _weaponModel.SelectedWeapon); @@ -129,6 +137,34 @@ public class WeaponController : Engine.Scene.Component.Component _weaponModel.SelectedWeaponIndex = parIndex; } + /// + /// Raycasts for the shooting pattern of the selected weapon. + /// + /// The position of the player or entity. + /// The forward direction of the player or entity. + /// The up direction of the player or entity. + /// The collider groups to consider for the raycast. + /// The raycast results. + public IEnumerable RaycastWeaponShooting(Vector3 parPosition, Vector3 parForward, Vector3 parUp, + HashSet parGroups) + { + var right = Vector3.Cross(parForward, parUp).Normalized(); + + var collisionManager = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent(); + + var offsets = WeaponData.ShootPattern.GetShootPattern(parForward, parUp, right); + foreach (var offset in offsets) + { + var direction = parForward + offset; + if (!collisionManager!.Raycast(parPosition, direction, parGroups, out var result)) + { + continue; + } + + yield return result; + } + } + /// /// Updates the view when the selected weapon changes. /// @@ -143,8 +179,13 @@ public class WeaponController : Engine.Scene.Component.Component parNewWeapon.OnAmmoChanged += AmmoChanged; _weaponView.UpdateView(parNewWeapon); + AmmoChanged(parNewWeapon); } + /// + /// Updates the ammo view when the selected weapon's ammo changes. + /// + /// The updated weapon. private void AmmoChanged(WeaponData parWeapon) { var ammoData = new AmmoData { Ammo = parWeapon.Ammo, MaxAmmo = parWeapon.MaxAmmo }; diff --git a/DoomDeathmatch/src/Component/UI/SelectorComponent.cs b/DoomDeathmatch/src/Component/UI/SelectorComponent.cs index 2ca50d3..5f18515 100644 --- a/DoomDeathmatch/src/Component/UI/SelectorComponent.cs +++ b/DoomDeathmatch/src/Component/UI/SelectorComponent.cs @@ -31,7 +31,7 @@ public class SelectorComponent : Engine.Scene.Component.Component /// /// The key used to select the currently selected item. /// - public KeyboardButtonCode SelectKey { get; set; } = KeyboardButtonCode.Space; + public KeyboardButtonCode SelectKey { get; set; } = KeyboardButtonCode.Enter; /// /// The input handler used to check for keyboard input. diff --git a/DoomDeathmatch/src/Component/Util/PlayerMovementComponent.cs b/DoomDeathmatch/src/Component/Util/PlayerMovementComponent.cs index 100c107..646bf2b 100644 --- a/DoomDeathmatch/src/Component/Util/PlayerMovementComponent.cs +++ b/DoomDeathmatch/src/Component/Util/PlayerMovementComponent.cs @@ -11,7 +11,7 @@ namespace DoomDeathmatch.Component.Util; public class PlayerMovementComponent : Engine.Scene.Component.Component { /// - /// The speed at which the player rotates. + /// The speed at which the player rotates in degrees per second. /// public float RotationSpeed { get; set; } = 110.0f; @@ -23,13 +23,13 @@ public class PlayerMovementComponent : Engine.Scene.Component.Component /// /// Controls the movement logic of the player. /// - private MovementController _movementController = null!; + private MovementComponent _movementComponent = null!; public override void Awake() { - _movementController = GameObject.GetComponent()!; + _movementComponent = GameObject.GetComponent()!; - ArgumentNullException.ThrowIfNull(_movementController); + ArgumentNullException.ThrowIfNull(_movementComponent); } public override void Update(double parDeltaTime) @@ -72,7 +72,7 @@ public class PlayerMovementComponent : Engine.Scene.Component.Component movement.Normalize(); movement = GameObject.Transform.Rotation * movement; - _movementController.ApplyMovement(movement); + _movementComponent.ApplyMovement(movement); } GameObject.Transform.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitZ, MathHelper.DegreesToRadians(rotation) * diff --git a/DoomDeathmatch/src/Scene/GameConstants.cs b/DoomDeathmatch/src/Scene/GameConstants.cs index 1616d06..ccfb74a 100644 --- a/DoomDeathmatch/src/Scene/GameConstants.cs +++ b/DoomDeathmatch/src/Scene/GameConstants.cs @@ -64,6 +64,7 @@ public static class GameConstants public const float PLAYER_BASE_HEALTH = 100; public const float PLAYER_BASE_SPEED = 10; + public const float PLAYER_BASE_ROTATION_SPEED = 110; #endregion diff --git a/DoomDeathmatch/src/Scene/Play/PlayScene.cs b/DoomDeathmatch/src/Scene/Play/PlayScene.cs index 0105776..3ee5d59 100644 --- a/DoomDeathmatch/src/Scene/Play/PlayScene.cs +++ b/DoomDeathmatch/src/Scene/Play/PlayScene.cs @@ -314,6 +314,10 @@ public static class PlayScene logoUi.Offset = new Vector2(0, 3f); parScene.AddChild(parentObject, logoObject); + var (pauseUiObject, pauseUi, _) = UiPrefabs.CreateTextUi(parScene, backgroundUiContainer, + UiPrefabs.GetDoomFont(), "Пауза", + parRenderLayer: RenderLayer.HUD, parScale: 1.5f); + var (backUiObject, backUi, _) = UiPrefabs.CreateTextUi(parScene, backgroundUiContainer, UiPrefabs.GetDoomFont(), "Назад", parRenderLayer: RenderLayer.HUD); @@ -328,7 +332,7 @@ public static class PlayScene var (stackObject, stack) = UiPrefabs.CreateStackUi(parScene, new StackComponent { - Offset = new Vector2(0, -1f), Container = backgroundUiContainer, Children = { backUi, exitUi } + Offset = new Vector2(0, -1f), Container = backgroundUiContainer, Children = { pauseUi, backUi, exitUi } }); stackObject.Transform.Size.Xy = new Vector2(1f, 6f); @@ -337,6 +341,8 @@ public static class PlayScene parScene.AddChild(parentObject, selectorObject); parScene.AddChild(parentObject, stackObject); + + parScene.AddChild(stackObject, pauseUiObject); parScene.AddChild(stackObject, backUiObject); parScene.AddChild(stackObject, exitUiObject); diff --git a/DoomDeathmatch/src/Scene/Play/Prefab/ConsumablePrefab.cs b/DoomDeathmatch/src/Scene/Play/Prefab/ConsumablePrefab.cs index dbdb086..5a259a4 100644 --- a/DoomDeathmatch/src/Scene/Play/Prefab/ConsumablePrefab.cs +++ b/DoomDeathmatch/src/Scene/Play/Prefab/ConsumablePrefab.cs @@ -32,7 +32,7 @@ public static class ConsumablePrefab new RigidbodyComponent(), new DragComponent { Drag = 10f, Multiplier = new Vector3(1, 1, 0) }, - new MovementController { Speed = 10f }, + new MovementComponent { Speed = 10f }, collider ] ); diff --git a/DoomDeathmatch/src/Scene/Play/Prefab/EnemyPrefab.cs b/DoomDeathmatch/src/Scene/Play/Prefab/EnemyPrefab.cs index dc7c556..9fa4422 100644 --- a/DoomDeathmatch/src/Scene/Play/Prefab/EnemyPrefab.cs +++ b/DoomDeathmatch/src/Scene/Play/Prefab/EnemyPrefab.cs @@ -32,7 +32,7 @@ public static class EnemyPrefab new HealthController(parEnemyData.BaseHealth), new EnemyHealthView(enemyHealthTextRenderer), - new MovementController(), + new MovementComponent(), new RigidbodyComponent(), new DragComponent { Drag = 5f, Multiplier = new Vector3(1, 1, 0) }, diff --git a/DoomDeathmatch/src/Scene/Play/Prefab/PlayerPrefab.cs b/DoomDeathmatch/src/Scene/Play/Prefab/PlayerPrefab.cs index 0201034..845645c 100644 --- a/DoomDeathmatch/src/Scene/Play/Prefab/PlayerPrefab.cs +++ b/DoomDeathmatch/src/Scene/Play/Prefab/PlayerPrefab.cs @@ -5,6 +5,7 @@ using DoomDeathmatch.Component.Physics; using DoomDeathmatch.Component.Physics.Collision; using DoomDeathmatch.Component.Util; using DoomDeathmatch.Script.Collision; +using DoomDeathmatch.Script.Model.Weapon; using Engine.Scene; using OpenTK.Mathematics; @@ -17,9 +18,6 @@ public static class PlayerPrefab var (perspectiveCameraObject, perspectiveCamera) = UiPrefabs.CreatePerspectiveCamera(parScene); perspectiveCameraObject.Transform.Translation.Z = 2; var playerObject = GameObjectUtil.CreateGameObject(parScene, [ - new PlayerMovementComponent(), - - new MovementController { Speed = GameConstants.PLAYER_BASE_SPEED }, new RigidbodyComponent(), new DragComponent { Drag = 10f, Multiplier = new Vector3(1, 1, 0) }, @@ -31,9 +29,12 @@ public static class PlayerPrefab ExcludeColliderCollideGroups = { "player" } }, + new MovementComponent { Speed = GameConstants.PLAYER_BASE_SPEED }, + new PlayerMovementComponent { RotationSpeed = GameConstants.PLAYER_BASE_ROTATION_SPEED }, + new PlayerController(perspectiveCamera), - new WeaponController(), + new WeaponController(WeaponData.Pistol), parWeaponView, new HealthController(GameConstants.PLAYER_BASE_HEALTH), diff --git a/DoomDeathmatch/src/Scene/UiPrefabs.cs b/DoomDeathmatch/src/Scene/UiPrefabs.cs index 0946a9f..b69face 100644 --- a/DoomDeathmatch/src/Scene/UiPrefabs.cs +++ b/DoomDeathmatch/src/Scene/UiPrefabs.cs @@ -43,12 +43,15 @@ public static class UiPrefabs public static (GameObject, UiContainerComponent, (GameObject, TextRenderer)) CreateTextUi(Engine.Scene.Scene parScene, UiContainerComponent parContainer, Font parFont, string parText, Align parAlign = Align.Center, - RenderLayer? parRenderLayer = null) + RenderLayer? parRenderLayer = null, float parScale = 1) { var size = parFont.Measure(parText); var outerObject = new GameObject { - Transform = { Size = new Vector3(size.X, size.Y, 1f), Translation = new Vector3(0, 0, -1) } + Transform = + { + Size = new Vector3(size.X, size.Y, 1f), Translation = new Vector3(0, 0, -1), Scale = new Vector3(parScale) + } }; var uiComponent = new UiContainerComponent { Container = parContainer }; outerObject.AddComponent(uiComponent); diff --git a/DoomDeathmatch/src/Script/Model/WeaponModel.cs b/DoomDeathmatch/src/Script/Model/WeaponModel.cs index 9726e2e..b8132de 100644 --- a/DoomDeathmatch/src/Script/Model/WeaponModel.cs +++ b/DoomDeathmatch/src/Script/Model/WeaponModel.cs @@ -48,10 +48,19 @@ public class WeaponModel /// /// The list of available weapons for the player or entity. /// - private readonly List _weapons = [WeaponData.Pistol]; + private readonly List _weapons; /// /// The index of the currently selected weapon in the weapons list. /// private int _selectedWeaponIndex; + + /// + /// Initializes a new instance of the class with an initial weapon. + /// + /// The initial weapon. + public WeaponModel(WeaponData parInitialWeapon) + { + _weapons = [parInitialWeapon]; + } } \ No newline at end of file diff --git a/PresenterConsole/assets/shader/ascii.shader b/PresenterConsole/assets/shader/ascii.shader index c58eef7..6e79aac 100644 --- a/PresenterConsole/assets/shader/ascii.shader +++ b/PresenterConsole/assets/shader/ascii.shader @@ -81,36 +81,36 @@ float perceptualColorDistance(vec3 color1, vec3 color2) { return dot(delta, delta); } -int findMostPerceptuallyAccurateColor(vec3 color) { - int bestMatchIndex = 0; - float minDistance = perceptualColorDistance(color, ConsoleColorVec3[0]); - - for (int i = 1; i < 16; i++) { - float currentDistance = perceptualColorDistance(color, ConsoleColorVec3[i]); - if (currentDistance < minDistance) { - minDistance = currentDistance; - bestMatchIndex = i; - } - } - - return bestMatchIndex; -} - //int findMostPerceptuallyAccurateColor(vec3 color) { -// int closestIndex = 0; -// float minDistance = distance(color, ConsoleColorVec3[0]); +// int bestMatchIndex = 0; +// float minDistance = perceptualColorDistance(color, ConsoleColorVec3[0]); // // for (int i = 1; i < 16; i++) { -// float dist = distance(color, ConsoleColorVec3[i]); -// if (dist < minDistance) { -// minDistance = dist; -// closestIndex = i; +// float currentDistance = perceptualColorDistance(color, ConsoleColorVec3[i]); +// if (currentDistance < minDistance) { +// minDistance = currentDistance; +// bestMatchIndex = i; // } // } // -// return closestIndex; +// return bestMatchIndex; //} +int findMostPerceptuallyAccurateColor(vec3 color) { + int closestIndex = 0; + float minDistance = distance(color, ConsoleColorVec3[0]); + + for (int i = 1; i < 16; i++) { + float dist = distance(color, ConsoleColorVec3[i]); + if (dist < minDistance) { + minDistance = dist; + closestIndex = i; + } + } + + return closestIndex; +} + // Enhanced luminosity calculation considering human perception float calculatePerceptualLuminance(vec3 color) { // BT.709 luminance coefficients with slight adjustment