reformat
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Engine\Engine.csproj" />
|
||||
<ProjectReference Include="..\Engine\Engine.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -39,16 +39,22 @@ public class ConsumableComponent : Engine.Scene.Component.Component
|
||||
private void OnCollision(AABBColliderComponent parCollider)
|
||||
{
|
||||
if (parCollider.ColliderGroups.Contains("player"))
|
||||
{
|
||||
TryConsume(parCollider);
|
||||
}
|
||||
else if (parCollider.ColliderGroups.Contains("consumable"))
|
||||
{
|
||||
MoveAway(parCollider);
|
||||
}
|
||||
}
|
||||
|
||||
private void TryConsume(AABBColliderComponent parCollider)
|
||||
{
|
||||
var playerController = parCollider.GameObject.GetComponent<PlayerController>();
|
||||
if (playerController == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_consumable.Consume(playerController);
|
||||
|
||||
@@ -61,17 +67,21 @@ public class ConsumableComponent : Engine.Scene.Component.Component
|
||||
parCollider.GameObject.Transform.GetFullTranslation();
|
||||
|
||||
if (direction.LengthSquared <= float.Epsilon)
|
||||
{
|
||||
direction = GetRandomDirection();
|
||||
}
|
||||
else
|
||||
{
|
||||
direction.Normalize();
|
||||
}
|
||||
|
||||
_movementController.ApplyMovement(direction);
|
||||
}
|
||||
|
||||
private Vector3 GetRandomDirection()
|
||||
{
|
||||
var x = _random.NextSingle() * 2 - 1;
|
||||
var y = _random.NextSingle() * 2 - 1;
|
||||
var x = (_random.NextSingle() * 2) - 1;
|
||||
var y = (_random.NextSingle() * 2) - 1;
|
||||
|
||||
return new Vector3(x, y, 0).Normalized();
|
||||
}
|
||||
|
||||
@@ -8,16 +8,15 @@ namespace DoomDeathmatch.Component.MVC.Enemy;
|
||||
|
||||
public class EnemyController : Engine.Scene.Component.Component
|
||||
{
|
||||
public HealthController HealthController => _healthController;
|
||||
|
||||
private GameController _gameController = null!;
|
||||
private HealthController _healthController = null!;
|
||||
private EnemyView _enemyView = null!;
|
||||
private MovementController _movementController = null!;
|
||||
private AttackBehavior _attackBehavior = null!;
|
||||
public HealthController HealthController { get; private set; } = null!;
|
||||
|
||||
private readonly EnemyData _enemyData;
|
||||
|
||||
private GameController _gameController = null!;
|
||||
private MovementController _movementController = null!;
|
||||
private AttackBehavior _attackBehavior = null!;
|
||||
private EnemyView _enemyView = null!;
|
||||
|
||||
public EnemyController(EnemyData parEnemyData)
|
||||
{
|
||||
_enemyData = parEnemyData;
|
||||
@@ -26,19 +25,19 @@ public class EnemyController : Engine.Scene.Component.Component
|
||||
public override void Awake()
|
||||
{
|
||||
_gameController = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<GameController>()!;
|
||||
_healthController = GameObject.GetComponent<HealthController>()!;
|
||||
HealthController = GameObject.GetComponent<HealthController>()!;
|
||||
_enemyView = GameObject.GetComponent<EnemyView>()!;
|
||||
_movementController = GameObject.GetComponent<MovementController>()!;
|
||||
|
||||
ArgumentNullException.ThrowIfNull(_gameController);
|
||||
ArgumentNullException.ThrowIfNull(_healthController);
|
||||
ArgumentNullException.ThrowIfNull(HealthController);
|
||||
ArgumentNullException.ThrowIfNull(_enemyView);
|
||||
ArgumentNullException.ThrowIfNull(_movementController);
|
||||
|
||||
_attackBehavior = _enemyData.AttackBehaviorCreator.Create(this, _gameController.PlayerController.HealthController);
|
||||
|
||||
_healthController.SetMaxHealth(_enemyData.BaseHealth);
|
||||
_healthController.OnDeath += OnDeath;
|
||||
HealthController.SetMaxHealth(_enemyData.BaseHealth);
|
||||
HealthController.OnDeath += OnDeath;
|
||||
_enemyView.UpdateView(_enemyData);
|
||||
_movementController.Speed = _enemyData.BaseSpeed;
|
||||
}
|
||||
@@ -47,7 +46,9 @@ public class EnemyController : Engine.Scene.Component.Component
|
||||
{
|
||||
var billboardComponent = GameObject.GetComponentInChildren<BillboardComponent>();
|
||||
if (billboardComponent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
billboardComponent.Target = _gameController.PlayerController.Camera.GameObject.Transform;
|
||||
}
|
||||
|
||||
@@ -9,16 +9,16 @@ namespace DoomDeathmatch.Component.MVC;
|
||||
|
||||
public class GameController : Engine.Scene.Component.Component
|
||||
{
|
||||
public bool IsPaused { get; private set; } = false;
|
||||
public bool IsGameOver { get; private set; } = false;
|
||||
public bool IsPaused { get; private set; }
|
||||
public bool IsGameOver { get; private set; }
|
||||
|
||||
public PlayerController PlayerController { get; private set; } = null!;
|
||||
public ScoreController ScoreController { get; private set; } = null!;
|
||||
|
||||
private TimerController _timerController = null!;
|
||||
|
||||
private readonly MenuControllerComponent _menuController;
|
||||
private readonly IInputHandler _inputHandler = EngineUtil.InputHandler;
|
||||
private readonly MenuControllerComponent _menuController;
|
||||
|
||||
private TimerController _timerController = null!;
|
||||
|
||||
public GameController(MenuControllerComponent parMenuController)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,9 @@ public class HealthView : Engine.Scene.Component.Component
|
||||
{
|
||||
var percentage = parHealthModel.Health / parHealthModel.MaxHealth * 100;
|
||||
if (parHealthModel.Health != 0)
|
||||
{
|
||||
percentage = Math.Max(1, percentage);
|
||||
}
|
||||
|
||||
_healthTextRenderer.Text = $"Здоровье: {percentage:000}";
|
||||
}
|
||||
|
||||
@@ -21,6 +21,6 @@ public class MovementController : Engine.Scene.Component.Component
|
||||
|
||||
public void ApplyMovement(Vector3 parDirection)
|
||||
{
|
||||
_rigidbody.AddForce(_dragComponent.Drag * Speed * parDirection.Normalized());
|
||||
_rigidbody.Force += _dragComponent.Drag * Speed * parDirection.Normalized();
|
||||
}
|
||||
}
|
||||
@@ -12,71 +12,77 @@ namespace DoomDeathmatch.Component.MVC;
|
||||
public class PlayerController : Engine.Scene.Component.Component
|
||||
{
|
||||
public event Action? OnDeath;
|
||||
public bool IsAlive => _healthController.IsAlive;
|
||||
|
||||
public HealthController HealthController => _healthController;
|
||||
public WeaponController WeaponController => _weaponController;
|
||||
public PerspectiveCamera Camera => _camera;
|
||||
public bool IsAlive => HealthController.IsAlive;
|
||||
public HealthController HealthController { get; private set; } = null!;
|
||||
public WeaponController WeaponController { get; private set; } = null!;
|
||||
public PerspectiveCamera Camera { get; }
|
||||
|
||||
private readonly IInputHandler _inputHandler = EngineUtil.InputHandler;
|
||||
|
||||
private HealthController _healthController = null!;
|
||||
private WeaponController _weaponController = null!;
|
||||
private readonly PerspectiveCamera _camera;
|
||||
|
||||
public PlayerController(PerspectiveCamera parCamera)
|
||||
{
|
||||
_camera = parCamera;
|
||||
Camera = parCamera;
|
||||
}
|
||||
|
||||
public override void Awake()
|
||||
{
|
||||
_healthController = GameObject.GetComponent<HealthController>()!;
|
||||
_weaponController = GameObject.GetComponent<WeaponController>()!;
|
||||
HealthController = GameObject.GetComponent<HealthController>()!;
|
||||
WeaponController = GameObject.GetComponent<WeaponController>()!;
|
||||
|
||||
ArgumentNullException.ThrowIfNull(_healthController);
|
||||
ArgumentNullException.ThrowIfNull(_weaponController);
|
||||
ArgumentNullException.ThrowIfNull(HealthController);
|
||||
ArgumentNullException.ThrowIfNull(WeaponController);
|
||||
|
||||
_healthController.OnDeath += () => OnDeath?.Invoke();
|
||||
HealthController.OnDeath += () => OnDeath?.Invoke();
|
||||
}
|
||||
|
||||
public override void Update(double parDeltaTime)
|
||||
{
|
||||
if (!IsAlive || parDeltaTime == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
if (KeyboardButtonCode.D1 + i > KeyboardButtonCode.D0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_inputHandler.IsKeyJustPressed(KeyboardButtonCode.D1 + i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_weaponController.SelectWeapon(i);
|
||||
WeaponController.SelectWeapon(i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (_inputHandler.IsKeyJustPressed(KeyboardButtonCode.Space))
|
||||
{
|
||||
if (!_weaponController.TryShoot())
|
||||
if (!WeaponController.TryShoot())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var position = _camera.GameObject.Transform.GetFullTranslation();
|
||||
var forward = (_camera.Forward - position).Normalized();
|
||||
var position = Camera.GameObject.Transform.GetFullTranslation();
|
||||
var forward = (Camera.Forward - position).Normalized();
|
||||
var right = Vector3.Cross(forward, Vector3.UnitZ).Normalized();
|
||||
|
||||
var collisionManager = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<CollisionManagerComponent>();
|
||||
|
||||
var offsets = _weaponController.WeaponData.ShootPattern.GetShootPattern(forward, Vector3.UnitZ, right);
|
||||
var offsets = WeaponController.WeaponData.ShootPattern.GetShootPattern(forward, Vector3.UnitZ, right);
|
||||
foreach (var offset in offsets)
|
||||
{
|
||||
var direction = forward + offset;
|
||||
if (!collisionManager!.Raycast(position, direction, ["enemy", "wall"], out var result))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var enemyController = result.HitObject.GetComponent<EnemyController>();
|
||||
enemyController?.HealthController.TakeDamage(_weaponController.WeaponData.Damage);
|
||||
enemyController?.HealthController.TakeDamage(WeaponController.WeaponData.Damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ public class TimerController : Engine.Scene.Component.Component
|
||||
public event Action? OnFinished;
|
||||
|
||||
private readonly TickableTimer _tickableTimer = new(60 + 10);
|
||||
|
||||
private TimerView _timerView = null!;
|
||||
|
||||
public override void Awake()
|
||||
|
||||
@@ -23,7 +23,9 @@ public class WeaponController : Engine.Scene.Component.Component
|
||||
public bool TryShoot()
|
||||
{
|
||||
if (_weaponModel.SelectedWeapon.Ammo <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_weaponModel.SelectedWeapon.Ammo--;
|
||||
|
||||
@@ -41,7 +43,9 @@ public class WeaponController : Engine.Scene.Component.Component
|
||||
public void AddWeapon(WeaponData parWeaponData)
|
||||
{
|
||||
if (_weaponModel.Weapons.Contains(parWeaponData))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_weaponModel.Weapons.Add(parWeaponData);
|
||||
}
|
||||
@@ -49,15 +53,21 @@ public class WeaponController : Engine.Scene.Component.Component
|
||||
public void AddOrMergeWeapon(WeaponData parWeaponData)
|
||||
{
|
||||
if (!_weaponModel.Weapons.Contains(parWeaponData))
|
||||
{
|
||||
_weaponModel.Weapons.Add(parWeaponData);
|
||||
}
|
||||
else
|
||||
{
|
||||
_weaponModel.Weapons.First(parData => parData.Id == parWeaponData.Id).Ammo += parWeaponData.Ammo;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveWeapon(int parIndex)
|
||||
{
|
||||
if (parIndex <= 0 || parIndex >= _weaponModel.Weapons.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var newSelectedIndex = parIndex >= _weaponModel.SelectedWeaponIndex ? _weaponModel.SelectedWeaponIndex : 0;
|
||||
|
||||
@@ -68,20 +78,19 @@ public class WeaponController : Engine.Scene.Component.Component
|
||||
public void SelectWeapon(int parIndex)
|
||||
{
|
||||
if (parIndex >= _weaponModel.Weapons.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_weaponModel.SelectedWeaponIndex = parIndex;
|
||||
}
|
||||
|
||||
// public WeaponData? FindWeapon(string parId)
|
||||
// {
|
||||
// return _weaponModel.Weapons.FirstOrDefault(parData => parData.Id == parId);
|
||||
// }
|
||||
|
||||
private void WeaponSelected(WeaponData? parOldWeapon, WeaponData parNewWeapon)
|
||||
{
|
||||
if (parOldWeapon != null)
|
||||
{
|
||||
parOldWeapon.OnAmmoChanged -= _weaponView.UpdateAmmoView;
|
||||
}
|
||||
|
||||
parNewWeapon.OnAmmoChanged += _weaponView.UpdateAmmoView;
|
||||
_weaponView.UpdateView(parNewWeapon);
|
||||
|
||||
@@ -12,9 +12,10 @@ public class WeaponView : Engine.Scene.Component.Component
|
||||
private readonly TextRenderer _weaponAmmo;
|
||||
private readonly Box2DRenderer _weaponSprite;
|
||||
|
||||
private AnimationPlayer<Texture>? _weaponFireAnimation;
|
||||
private Texture? _idleTexture;
|
||||
|
||||
private AnimationPlayer<Texture>? _weaponFireAnimation;
|
||||
|
||||
public WeaponView(TextRenderer parWeaponName, TextRenderer parWeaponAmmo, Box2DRenderer parWeaponSprite)
|
||||
{
|
||||
_weaponName = parWeaponName;
|
||||
|
||||
@@ -16,13 +16,17 @@ public class ColliderForceFieldComponent : Engine.Scene.Component.Component
|
||||
{
|
||||
var rigidbody = parCollider.GameObject.GetComponent<RigidbodyComponent>();
|
||||
if (rigidbody == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var normal = _collider.Collider.GetCollisionNormal(parCollider.Collider);
|
||||
var speedAlongNormal = Vector3.Dot(rigidbody.Velocity, normal);
|
||||
if (speedAlongNormal > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rigidbody.AddVelocity(-normal * (speedAlongNormal * 1.75f));
|
||||
rigidbody.Velocity -= normal * (speedAlongNormal * 1.75f);
|
||||
}
|
||||
}
|
||||
@@ -30,16 +30,24 @@ public class CollisionManagerComponent : Engine.Scene.Component.Component
|
||||
!colliderA.ColliderGroups.Overlaps(colliderB.ExcludeColliderCollideGroups);
|
||||
|
||||
if (!canCollideAB && !canCollideBA)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!colliderA.Collider.Intersects(colliderB.Collider))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (canCollideAB)
|
||||
{
|
||||
colliderA.CollideWith(colliderB);
|
||||
}
|
||||
|
||||
if (canCollideBA)
|
||||
{
|
||||
colliderB.CollideWith(colliderA);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,14 +64,20 @@ public class CollisionManagerComponent : Engine.Scene.Component.Component
|
||||
foreach (var collider in _colliders)
|
||||
{
|
||||
if (!collider.ColliderGroups.Overlaps(parColliderGroups))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!RaycastAABB(start, direction, collider.Collider, out var hitPoint, out var normal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var distance = (start - hitPoint).Length;
|
||||
if (distance > closestDistance)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
closestDistance = distance;
|
||||
|
||||
@@ -128,9 +142,13 @@ public class CollisionManagerComponent : Engine.Scene.Component.Component
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
if (quadrant[i] != MIDDLE && parDirection[i] != 0.0f)
|
||||
{
|
||||
maxT[i] = (candidatePlane[i] - parOrigin[i]) / parDirection[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
maxT[i] = -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Get largest of the maxT's for final choice of intersection
|
||||
@@ -138,26 +156,32 @@ public class CollisionManagerComponent : Engine.Scene.Component.Component
|
||||
for (var i = 1; i < 3; i++)
|
||||
{
|
||||
if (maxT[whichPlane] < maxT[i])
|
||||
{
|
||||
whichPlane = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Check final candidate actually inside box
|
||||
if (maxT[whichPlane] < 0.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
if (whichPlane != i)
|
||||
{
|
||||
parHitPoint[i] = parOrigin[i] + maxT[whichPlane] * parDirection[i];
|
||||
parHitPoint[i] = parOrigin[i] + (maxT[whichPlane] * parDirection[i]);
|
||||
if (parHitPoint[i] < minB[i] || parHitPoint[i] > maxB[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parHitPoint[i] = candidatePlane[i];
|
||||
// Calculate normal for the intersection plane
|
||||
parHitNormal[i] = (quadrant[i] == LEFT) ? -1.0f : 1.0f;
|
||||
parHitNormal[i] = quadrant[i] == LEFT ? -1.0f : 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,6 @@ public class DragComponent : Engine.Scene.Component.Component
|
||||
|
||||
public override void Update(double parDeltaTime)
|
||||
{
|
||||
_rigidbody.AddForce(-Drag * (_rigidbody.Velocity * Multiplier));
|
||||
_rigidbody.Force -= Drag * (_rigidbody.Velocity * Multiplier);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ namespace DoomDeathmatch.Component.Physics;
|
||||
|
||||
public class GravityComponent : Engine.Scene.Component.Component
|
||||
{
|
||||
public bool IsInAir { get; private set; }
|
||||
|
||||
public float Strength { get; set; } = 10.0f;
|
||||
|
||||
public Vector3 Direction
|
||||
@@ -14,7 +16,6 @@ public class GravityComponent : Engine.Scene.Component.Component
|
||||
|
||||
public float Floor { get; set; } = 5.0f;
|
||||
|
||||
public bool IsInAir { get; private set; } = false;
|
||||
|
||||
private RigidbodyComponent _rigidbody = null!;
|
||||
private Vector3 _direction = -Vector3.UnitZ;
|
||||
@@ -34,13 +35,15 @@ public class GravityComponent : Engine.Scene.Component.Component
|
||||
IsInAir = false;
|
||||
var velocityAlongDirection = Vector3.Dot(_rigidbody.Velocity, Direction);
|
||||
if (velocityAlongDirection > 0)
|
||||
_rigidbody.AddVelocity(-velocityAlongDirection * Direction);
|
||||
{
|
||||
_rigidbody.Velocity -= velocityAlongDirection * Direction;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
IsInAir = true;
|
||||
var gravity = Strength * Direction;
|
||||
_rigidbody.AddForce(gravity);
|
||||
_rigidbody.Force += gravity;
|
||||
}
|
||||
}
|
||||
@@ -4,35 +4,50 @@ namespace DoomDeathmatch.Component.Physics;
|
||||
|
||||
public class RigidbodyComponent : Engine.Scene.Component.Component
|
||||
{
|
||||
public Vector3 Velocity { get; private set; } = Vector3.Zero;
|
||||
public Vector3 Acceleration { get; private set; } = Vector3.Zero;
|
||||
public Vector3 Force { get; private set; } = Vector3.Zero;
|
||||
public float Mass { get; set; } = 1.0f;
|
||||
public bool IsStatic { get; set; } = false;
|
||||
|
||||
public void AddForce(Vector3 parForce)
|
||||
public Vector3 Force
|
||||
{
|
||||
if (IsStatic)
|
||||
return;
|
||||
get => _force;
|
||||
set
|
||||
{
|
||||
if (IsStatic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Force += parForce;
|
||||
_force = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddVelocity(Vector3 parVelocity)
|
||||
public Vector3 Velocity
|
||||
{
|
||||
if (IsStatic)
|
||||
return;
|
||||
get => _velocity;
|
||||
set
|
||||
{
|
||||
if (IsStatic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Velocity += parVelocity;
|
||||
_velocity = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 _force = Vector3.Zero;
|
||||
private Vector3 _velocity = Vector3.Zero;
|
||||
private Vector3 _acceleration = Vector3.Zero;
|
||||
|
||||
public override void Update(double parDeltaTime)
|
||||
{
|
||||
if (IsStatic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Acceleration = Force / Mass;
|
||||
Velocity += Acceleration * (float)parDeltaTime;
|
||||
_acceleration = Force / Mass;
|
||||
Velocity += _acceleration * (float)parDeltaTime;
|
||||
GameObject.Transform.Translation += Velocity * (float)parDeltaTime;
|
||||
|
||||
Force = Vector3.Zero;
|
||||
|
||||
@@ -5,18 +5,16 @@ namespace DoomDeathmatch.Component.UI;
|
||||
|
||||
public class SelectorComponent : Engine.Scene.Component.Component
|
||||
{
|
||||
public List<UiComponent> Children => _children;
|
||||
public KeyboardButtonCode SelectKey { get; set; } = KeyboardButtonCode.Space;
|
||||
public event Action<UiComponent>? OnSelect;
|
||||
|
||||
public List<UiComponent> Children { get; } = [];
|
||||
public KeyboardButtonCode NextKey { get; set; } = KeyboardButtonCode.Down;
|
||||
public KeyboardButtonCode PrevKey { get; set; } = KeyboardButtonCode.Up;
|
||||
|
||||
public event Action<UiComponent>? OnSelect;
|
||||
public KeyboardButtonCode SelectKey { get; set; } = KeyboardButtonCode.Space;
|
||||
|
||||
private readonly IInputHandler _inputHandler = EngineUtil.InputHandler;
|
||||
|
||||
private readonly List<UiComponent> _children = [];
|
||||
|
||||
private int _selectedIndex = 0;
|
||||
private int _selectedIndex;
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
@@ -31,13 +29,17 @@ public class SelectorComponent : Engine.Scene.Component.Component
|
||||
public override void Update(double parDeltaTime)
|
||||
{
|
||||
if (_inputHandler.IsKeyJustPressed(SelectKey))
|
||||
_children[_selectedIndex].InvokeClick();
|
||||
{
|
||||
Children[_selectedIndex].InvokeClick();
|
||||
}
|
||||
|
||||
if (_inputHandler.IsKeyJustPressed(NextKey))
|
||||
{
|
||||
_selectedIndex++;
|
||||
if (_selectedIndex >= Children.Count)
|
||||
{
|
||||
_selectedIndex = 0;
|
||||
}
|
||||
|
||||
SelectionChanged();
|
||||
}
|
||||
@@ -46,7 +48,9 @@ public class SelectorComponent : Engine.Scene.Component.Component
|
||||
{
|
||||
_selectedIndex--;
|
||||
if (_selectedIndex < 0)
|
||||
{
|
||||
_selectedIndex = Children.Count - 1;
|
||||
}
|
||||
|
||||
SelectionChanged();
|
||||
}
|
||||
@@ -77,10 +81,14 @@ public class SelectorComponent : Engine.Scene.Component.Component
|
||||
{
|
||||
var index = Children.IndexOf(parComponent);
|
||||
if (index < 0)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
if (index == _selectedIndex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_selectedIndex = index;
|
||||
|
||||
|
||||
@@ -5,25 +5,23 @@ namespace DoomDeathmatch.Component.UI;
|
||||
|
||||
public class StackComponent : UiContainerComponent
|
||||
{
|
||||
public List<UiComponent> Children => _children;
|
||||
public List<UiComponent> Children { get; } = [];
|
||||
public Orientation Orientation { get; set; } = Orientation.Vertical;
|
||||
|
||||
private readonly List<UiComponent> _children = [];
|
||||
|
||||
public override void Update(double parDeltaTime)
|
||||
{
|
||||
base.Update(parDeltaTime);
|
||||
|
||||
var size = GameObject.Transform.Size.Xy;
|
||||
var count = _children.Count;
|
||||
var count = Children.Count;
|
||||
|
||||
size *= Orientation == Orientation.Horizontal ? new Vector2(1, 0) : new Vector2(0, 1);
|
||||
|
||||
var offset = new Vector2(-size.X / 2 + size.X / count / 2, -size.Y / 2 + size.Y / count / 2);
|
||||
var offset = new Vector2((-size.X / 2) + (size.X / count / 2), (-size.Y / 2) + (size.Y / count / 2));
|
||||
|
||||
for (var i = count - 1; i >= 0; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
var child = Children[i];
|
||||
|
||||
child.Offset = offset;
|
||||
offset += size / count;
|
||||
|
||||
@@ -9,7 +9,6 @@ public class TextAlignComponent : Engine.Scene.Component.Component
|
||||
public Align Alignment { get; set; } = Align.Left;
|
||||
|
||||
private TextRenderer _textRenderer = null!;
|
||||
|
||||
private string? _cachedText;
|
||||
|
||||
public override void Awake()
|
||||
@@ -20,10 +19,14 @@ public class TextAlignComponent : Engine.Scene.Component.Component
|
||||
public override void Update(double parDeltaTime)
|
||||
{
|
||||
if (_textRenderer.Text == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_cachedText == _textRenderer.Text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_cachedText = _textRenderer.Text;
|
||||
var font = _textRenderer.Font;
|
||||
|
||||
@@ -12,40 +12,37 @@ public class TextInputComponent : Engine.Scene.Component.Component
|
||||
|
||||
public float InputDelay
|
||||
{
|
||||
get => _inputDelay;
|
||||
set
|
||||
{
|
||||
_inputDelay = value;
|
||||
_inputTimer.TotalTime = value;
|
||||
}
|
||||
get => (float)_inputTimer.TotalTime;
|
||||
set => _inputTimer.TotalTime = value;
|
||||
}
|
||||
|
||||
private readonly IInputHandler _inputHandler = EngineUtil.InputHandler;
|
||||
|
||||
private readonly KeyboardButtonCode[] _acceptedKeys =
|
||||
KeyboardButtonCodeHelper.GetAllPrintableKeys().Append(KeyboardButtonCode.Backspace).ToArray();
|
||||
|
||||
private readonly IInputHandler _inputHandler = EngineUtil.InputHandler;
|
||||
private readonly TickableTimer _inputTimer;
|
||||
private float _inputDelay = 0;
|
||||
private readonly HashSet<KeyboardButtonCode> _lastKeys = [];
|
||||
|
||||
public TextInputComponent(float parInputDelay = 0.2f)
|
||||
{
|
||||
_inputDelay = parInputDelay;
|
||||
_inputTimer = new TickableTimer(_inputDelay) { CurrentTime = 0 };
|
||||
_inputTimer = new TickableTimer(parInputDelay) { CurrentTime = 0 };
|
||||
}
|
||||
|
||||
public override void Update(double parDeltaTime)
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_inputTimer.Update(parDeltaTime);
|
||||
|
||||
foreach (var key in _acceptedKeys)
|
||||
{
|
||||
if (_lastKeys.Contains(key) && !_inputTimer.IsFinished)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_inputHandler.IsKeyPressed(key))
|
||||
{
|
||||
@@ -69,7 +66,9 @@ public class TextInputComponent : Engine.Scene.Component.Component
|
||||
}
|
||||
|
||||
if (invoke)
|
||||
{
|
||||
OnInput?.Invoke(Input);
|
||||
}
|
||||
|
||||
_lastKeys.Add(key);
|
||||
|
||||
|
||||
@@ -8,14 +8,14 @@ namespace DoomDeathmatch.Component.UI;
|
||||
|
||||
public class UiComponent : Engine.Scene.Component.Component
|
||||
{
|
||||
public UiContainerComponent? Container { get; set; }
|
||||
public Anchor Anchor { get; set; } = Anchor.Center;
|
||||
public Vector2 Offset { get; set; } = Vector2.Zero;
|
||||
public Anchor Center { get; set; } = Anchor.Center;
|
||||
|
||||
public event Action<UiComponent>? OnClick;
|
||||
public event Action<UiComponent>? OnMouseOver;
|
||||
|
||||
public UiContainerComponent? Container { get; set; }
|
||||
public Anchor Center { get; set; } = Anchor.Center;
|
||||
public Anchor Anchor { get; set; } = Anchor.Center;
|
||||
public Vector2 Offset { get; set; } = Vector2.Zero;
|
||||
|
||||
private readonly IInputHandler _inputHandler = EngineUtil.InputHandler;
|
||||
|
||||
public override void Update(double parDeltaTime)
|
||||
|
||||
@@ -7,11 +7,11 @@ namespace DoomDeathmatch.Component.UI;
|
||||
|
||||
public class UiContainerComponent : UiComponent
|
||||
{
|
||||
private readonly IInputHandler _inputHandler = EngineUtil.InputHandler;
|
||||
|
||||
public Camera? Camera { get; set; }
|
||||
public Vector3 MousePosition { get; private set; }
|
||||
|
||||
private readonly IInputHandler _inputHandler = EngineUtil.InputHandler;
|
||||
|
||||
public override void Update(double parDeltaTime)
|
||||
{
|
||||
base.Update(parDeltaTime);
|
||||
|
||||
@@ -21,11 +21,15 @@ public class BillboardComponent : Engine.Scene.Component.Component
|
||||
var forward = targetPosition - currentPosition;
|
||||
forward -= Vector3.Dot(forward, Up) * Up;
|
||||
if (forward.LengthSquared > 0)
|
||||
{
|
||||
forward.Normalize();
|
||||
}
|
||||
|
||||
var right = Vector3.Cross(Up, forward);
|
||||
if (right.LengthSquared > 0)
|
||||
{
|
||||
right.Normalize();
|
||||
}
|
||||
|
||||
var recalculatedUp = Vector3.Cross(forward, right).Normalized();
|
||||
|
||||
|
||||
@@ -5,21 +5,29 @@ namespace DoomDeathmatch.Component.Util;
|
||||
|
||||
public class CopySizeComponent : Engine.Scene.Component.Component
|
||||
{
|
||||
public Vector3 Multiplier { get; set; } = Vector3.One;
|
||||
public Transform? Target { get; set; }
|
||||
public Vector3 Multiplier { get; set; } = Vector3.One;
|
||||
|
||||
public override void Update(double parDeltaTime)
|
||||
{
|
||||
if (Target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Multiplier.X != 0)
|
||||
{
|
||||
GameObject.Transform.Size.X = Target.Size.X * Multiplier.X;
|
||||
}
|
||||
|
||||
if (Multiplier.Y != 0)
|
||||
{
|
||||
GameObject.Transform.Size.Y = Target.Size.Y * Multiplier.Y;
|
||||
}
|
||||
|
||||
if (Multiplier.Z != 0)
|
||||
{
|
||||
GameObject.Transform.Size.Z = Target.Size.Z * Multiplier.Z;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ public class PlayerMovementComponent : Engine.Scene.Component.Component
|
||||
public float RotationSpeed { get; set; } = 110.0f;
|
||||
|
||||
private readonly IInputHandler _inputHandler = EngineUtil.InputHandler;
|
||||
|
||||
private MovementController _movementController = null!;
|
||||
|
||||
public override void Awake()
|
||||
@@ -25,18 +26,34 @@ public class PlayerMovementComponent : Engine.Scene.Component.Component
|
||||
var rotation = 0.0f;
|
||||
|
||||
if (_inputHandler.IsKeyPressed(KeyboardButtonCode.W))
|
||||
{
|
||||
movement.Y += 1;
|
||||
}
|
||||
|
||||
if (_inputHandler.IsKeyPressed(KeyboardButtonCode.S))
|
||||
{
|
||||
movement.Y -= 1;
|
||||
}
|
||||
|
||||
if (_inputHandler.IsKeyPressed(KeyboardButtonCode.D))
|
||||
{
|
||||
movement.X += 1;
|
||||
}
|
||||
|
||||
if (_inputHandler.IsKeyPressed(KeyboardButtonCode.A))
|
||||
{
|
||||
movement.X -= 1;
|
||||
}
|
||||
|
||||
if (_inputHandler.IsKeyPressed(KeyboardButtonCode.Q))
|
||||
{
|
||||
rotation += RotationSpeed;
|
||||
}
|
||||
|
||||
if (_inputHandler.IsKeyPressed(KeyboardButtonCode.E))
|
||||
{
|
||||
rotation -= RotationSpeed;
|
||||
}
|
||||
|
||||
if (movement.LengthSquared > 0)
|
||||
{
|
||||
|
||||
@@ -41,7 +41,9 @@ public static class GameOverScene
|
||||
nextUi.OnClick += _ =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(nameInputComponent.Input))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SubmitScore(nameInputComponent.Input, parScore);
|
||||
EngineUtil.SceneManager.TransitionTo(MainScene.Create);
|
||||
|
||||
@@ -100,7 +100,7 @@ public static class MainScene
|
||||
backUi.OnClick += _ => parMenuController.SelectMenuItem("main");
|
||||
|
||||
var (stackObject, stack) = UiUtil.CreateStackUi(parScene,
|
||||
new StackComponent { Offset = new Vector2(0, -1.5f), Container = parUiContainer, Children = { } });
|
||||
new StackComponent { Offset = new Vector2(0, -1.5f), Container = parUiContainer });
|
||||
stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
|
||||
|
||||
var leadersTable = CreateLeadersTable(parScene, parUiContainer, EngineUtil.DataFolder);
|
||||
@@ -134,7 +134,9 @@ public static class MainScene
|
||||
{
|
||||
leadersTableList.Add(CreateLeadersRow(parScene, parUiContainer, row.Name, row.Score.ToString()));
|
||||
if (++rows >= 5)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return leadersTableList;
|
||||
|
||||
@@ -63,7 +63,7 @@ public static class PlayScene
|
||||
new ScoreController(),
|
||||
playScoreView,
|
||||
|
||||
new CollisionManagerComponent(),
|
||||
new CollisionManagerComponent()
|
||||
]);
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ public static class PlayScene
|
||||
}
|
||||
|
||||
var size = max - min;
|
||||
var offset = min + size / 2;
|
||||
var offset = min + (size / 2);
|
||||
|
||||
var colliderObject = GameObjectUtil.CreateColliderForceField(
|
||||
parScene,
|
||||
|
||||
@@ -57,7 +57,7 @@ public static class EnemyPrefab
|
||||
var enemyVisualObject = GameObjectUtil.CreateGameObject(parScene,
|
||||
new Transform { Translation = new Vector3(0, 0f, 1f), Size = new Vector3(1, 2, 1) }, [
|
||||
enemyBox2DRenderer,
|
||||
new BillboardComponent(),
|
||||
new BillboardComponent()
|
||||
]
|
||||
);
|
||||
|
||||
@@ -72,7 +72,7 @@ public static class EnemyPrefab
|
||||
Vector3 parVelocity, float parDamage, Transform? parBillboardTarget = null)
|
||||
{
|
||||
var rigidbodyComponent = new RigidbodyComponent();
|
||||
rigidbodyComponent.AddVelocity(parVelocity);
|
||||
rigidbodyComponent.Velocity += parVelocity;
|
||||
|
||||
var fireballObject = GameObjectUtil.CreateGameObject(parScene,
|
||||
new Transform { Translation = parPosition, Size = new Vector3(0.5f) },
|
||||
|
||||
@@ -37,7 +37,7 @@ public static class PlayerPrefab
|
||||
parWeaponView,
|
||||
|
||||
new HealthController(),
|
||||
parHealthView,
|
||||
parHealthView
|
||||
]);
|
||||
|
||||
parScene.AddChild(playerObject, perspectiveCameraObject);
|
||||
|
||||
@@ -5,29 +5,25 @@ namespace DoomDeathmatch.Script;
|
||||
|
||||
public class AnimationPlayer<T>(float parInterval) : IUpdate
|
||||
{
|
||||
public List<T> Frames { get; init; } = [];
|
||||
public bool IsPlaying { get; private set; } = false;
|
||||
public int NextFrame { get; private set; } = 0;
|
||||
|
||||
public event Action<T>? OnFrameChanged;
|
||||
public event Action? OnFinish;
|
||||
public event Action<T>? OnFrameChanged;
|
||||
|
||||
public bool IsPlaying { get; private set; }
|
||||
public List<T> Frames { get; init; } = [];
|
||||
public int NextFrame { get; private set; }
|
||||
|
||||
private readonly TickableTimer _timer = new(parInterval);
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Reset();
|
||||
IsPlaying = true;
|
||||
}
|
||||
|
||||
public void Update(double parDeltaTime)
|
||||
{
|
||||
if (!IsPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_timer.Update(parDeltaTime);
|
||||
|
||||
if (_timer.CurrentTime < _timer.TotalTime * (1.0f - 1.0f / Frames.Count * NextFrame))
|
||||
if (_timer.CurrentTime < _timer.TotalTime * (1.0f - (1.0f / Frames.Count * NextFrame)))
|
||||
{
|
||||
OnFrameChanged?.Invoke(Frames[NextFrame]);
|
||||
NextFrame++;
|
||||
@@ -41,6 +37,12 @@ public class AnimationPlayer<T>(float parInterval) : IUpdate
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Reset();
|
||||
IsPlaying = true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_timer.Reset();
|
||||
|
||||
@@ -4,11 +4,11 @@ namespace DoomDeathmatch.Script.Collision;
|
||||
|
||||
public class AABBCollider
|
||||
{
|
||||
public Vector3 Size { get; set; }
|
||||
public Vector3 Position { get; set; }
|
||||
public Vector3 Size { get; set; }
|
||||
|
||||
public Vector3 Max => Position + Size / 2;
|
||||
public Vector3 Min => Position - Size / 2;
|
||||
public Vector3 Min => Position - (Size / 2);
|
||||
public Vector3 Max => Position + (Size / 2);
|
||||
|
||||
public bool Intersects(AABBCollider parCollider)
|
||||
{
|
||||
@@ -27,9 +27,9 @@ public class AABBCollider
|
||||
var diff = parOther.Position - Position;
|
||||
|
||||
// Calculate penetration depths for each axis
|
||||
var penX = (Size.X / 2 + parOther.Size.X / 2) - Math.Abs(diff.X);
|
||||
var penY = (Size.Y / 2 + parOther.Size.Y / 2) - Math.Abs(diff.Y);
|
||||
var penZ = (Size.Z / 2 + parOther.Size.Z / 2) - Math.Abs(diff.Z);
|
||||
var penX = (Size.X / 2) + (parOther.Size.X / 2) - Math.Abs(diff.X);
|
||||
var penY = (Size.Y / 2) + (parOther.Size.Y / 2) - Math.Abs(diff.Y);
|
||||
var penZ = (Size.Z / 2) + (parOther.Size.Z / 2) - Math.Abs(diff.Z);
|
||||
|
||||
// Use the axis with the smallest penetration
|
||||
if (penX < penY && penX < penZ)
|
||||
|
||||
@@ -8,5 +8,6 @@ public class RaycastResult
|
||||
public float Distance { get; init; }
|
||||
public Vector3 HitPoint { get; init; }
|
||||
public Vector3 Normal { get; init; }
|
||||
|
||||
public GameObject HitObject { get; init; }
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace DoomDeathmatch.Script.Condition;
|
||||
public class TickableTimerCondition : ICondition
|
||||
{
|
||||
public event Action? OnTrue;
|
||||
|
||||
public bool IsTrue => _timer.IsFinished;
|
||||
|
||||
private readonly TickableTimer _timer;
|
||||
|
||||
@@ -19,7 +19,9 @@ public abstract class CooldownAttackBehavior(
|
||||
if (CanAttack())
|
||||
{
|
||||
if (!_tickableTimer.IsFinished)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var result = ActivateAttack();
|
||||
|
||||
|
||||
@@ -63,10 +63,13 @@ public class EnemyData
|
||||
|
||||
public string Id { get; private init; } = "";
|
||||
public string Name { get; private init; } = "";
|
||||
|
||||
public string Texture { get; private init; } = "";
|
||||
|
||||
public float BaseHealth { get; private init; }
|
||||
public int BaseScore { get; private init; }
|
||||
public float BaseSpeed { get; private init; }
|
||||
|
||||
public IMovementBehavior MovementBehavior { get; private init; }
|
||||
public IAttackBehaviorCreator AttackBehaviorCreator { get; private init; }
|
||||
|
||||
|
||||
@@ -7,6 +7,6 @@ public class FollowPlayerMovementBehavior(float parRadius) : IMovementBehavior
|
||||
public Vector3 GetNextPosition(Vector3 parPosition, Vector3 parPlayerPosition)
|
||||
{
|
||||
var direction = (parPosition - parPlayerPosition).Normalized();
|
||||
return parPlayerPosition + parRadius * direction;
|
||||
return parPlayerPosition + (parRadius * direction);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,24 @@
|
||||
|
||||
public class HealthModel
|
||||
{
|
||||
public event Action<HealthModel>? HealthChanged;
|
||||
|
||||
public float Health
|
||||
{
|
||||
get => _health;
|
||||
set
|
||||
{
|
||||
value = Math.Clamp(value, 0, MaxHealth);
|
||||
if (Math.Abs(_health - value) < float.Epsilon)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_health = value;
|
||||
HealthChanged?.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
||||
public float MaxHealth
|
||||
{
|
||||
get => _maxHealth;
|
||||
@@ -13,22 +31,6 @@ public class HealthModel
|
||||
}
|
||||
}
|
||||
|
||||
public float Health
|
||||
{
|
||||
get => _health;
|
||||
set
|
||||
{
|
||||
value = Math.Clamp(value, 0, MaxHealth);
|
||||
if (Math.Abs(_health - value) < float.Epsilon)
|
||||
return;
|
||||
|
||||
_health = value;
|
||||
HealthChanged?.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<HealthModel>? HealthChanged;
|
||||
|
||||
private float _health;
|
||||
private float _maxHealth;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ public class RandomFlatSpreadShootPattern(float parAngle, uint parCount) : IShoo
|
||||
{
|
||||
for (var i = 0; i < parCount; i++)
|
||||
{
|
||||
var angle = parAngle * ((float)_random.NextDouble() * 2 - 1);
|
||||
var angle = parAngle * (((float)_random.NextDouble() * 2) - 1);
|
||||
var delta = MathF.Tan(angle);
|
||||
|
||||
var offset = parRight * delta;
|
||||
|
||||
@@ -13,7 +13,7 @@ public class WeaponData
|
||||
FireAnimationDuration = 0.25f,
|
||||
FireAnimation =
|
||||
{
|
||||
"texture/pistol/fire1.png", "texture/pistol/fire2.png", "texture/pistol/fire3.png", "texture/pistol/fire4.png",
|
||||
"texture/pistol/fire1.png", "texture/pistol/fire2.png", "texture/pistol/fire3.png", "texture/pistol/fire4.png"
|
||||
},
|
||||
Damage = 30,
|
||||
ShootPattern = new LineShootPattern()
|
||||
@@ -31,14 +31,11 @@ public class WeaponData
|
||||
ShootPattern = new RandomFlatSpreadShootPattern(MathHelper.DegreesToRadians(10), 40)
|
||||
};
|
||||
|
||||
public event Action<WeaponData>? OnAmmoChanged;
|
||||
|
||||
|
||||
public string Id { get; private init; } = "";
|
||||
public string Name { get; private init; } = "";
|
||||
public string IdleTexture { get; private init; } = "";
|
||||
public float FireAnimationDuration { get; private init; } = 0;
|
||||
public List<string> FireAnimation { get; private init; } = [];
|
||||
public int Damage { get; private init; }
|
||||
public int MaxAmmo { get; }
|
||||
public IShootPattern ShootPattern { get; private init; }
|
||||
|
||||
public int Ammo
|
||||
{
|
||||
@@ -46,19 +43,34 @@ public class WeaponData
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
if (value > MaxAmmo)
|
||||
{
|
||||
value = MaxAmmo;
|
||||
}
|
||||
|
||||
if (_ammo == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ammo = value;
|
||||
OnAmmoChanged?.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<WeaponData>? OnAmmoChanged;
|
||||
public int MaxAmmo { get; }
|
||||
|
||||
public int Damage { get; private init; }
|
||||
|
||||
public string IdleTexture { get; private init; } = "";
|
||||
public float FireAnimationDuration { get; private init; }
|
||||
public List<string> FireAnimation { get; } = [];
|
||||
|
||||
public IShootPattern ShootPattern { get; private init; }
|
||||
|
||||
private int _ammo;
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ public class WeaponModel
|
||||
public event Action<WeaponData, WeaponData>? OnWeaponSelected;
|
||||
|
||||
public IList<WeaponData> Weapons => _weapons;
|
||||
|
||||
public WeaponData SelectedWeapon => _weapons[_selectedWeaponIndex];
|
||||
|
||||
public int SelectedWeaponIndex
|
||||
@@ -18,7 +17,9 @@ public class WeaponModel
|
||||
value = Math.Clamp(value, 0, _weapons.Count - 1);
|
||||
|
||||
if (_selectedWeaponIndex == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var oldSelectedWeapon = SelectedWeapon;
|
||||
_selectedWeaponIndex = value;
|
||||
@@ -27,5 +28,6 @@ public class WeaponModel
|
||||
}
|
||||
|
||||
private readonly List<WeaponData> _weapons = [WeaponData.Pistol];
|
||||
private int _selectedWeaponIndex = 0;
|
||||
|
||||
private int _selectedWeaponIndex;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ public class WeightedRandomValueProvider<T> : IValueProvider<T>
|
||||
{
|
||||
private readonly List<(int, IValueProvider<T>)> _providers = [];
|
||||
private readonly Random _random = new();
|
||||
private readonly int _totalWeight = 0;
|
||||
private readonly int _totalWeight;
|
||||
|
||||
public WeightedRandomValueProvider(IEnumerable<(int, IValueProvider<T>)> parProviders)
|
||||
{
|
||||
@@ -15,7 +15,9 @@ public class WeightedRandomValueProvider<T> : IValueProvider<T>
|
||||
}
|
||||
|
||||
if (_totalWeight <= 0)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(WeightedRandomValueProvider<T>)} is empty");
|
||||
}
|
||||
}
|
||||
|
||||
public T GetValue()
|
||||
@@ -25,7 +27,9 @@ public class WeightedRandomValueProvider<T> : IValueProvider<T>
|
||||
foreach (var (weight, provider) in _providers)
|
||||
{
|
||||
if (random < weight)
|
||||
{
|
||||
return provider.GetValue();
|
||||
}
|
||||
|
||||
random -= weight;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ namespace DoomDeathmatch.Script.Score;
|
||||
[JsonSerializable(typeof(ScoreTable))]
|
||||
public class ScoreTable
|
||||
{
|
||||
private static readonly JsonSerializerOptions OPTIONS = new() { Converters = { new ScoreTableJsonConverter() } };
|
||||
|
||||
public List<ScoreRow> Rows { get; } = new();
|
||||
|
||||
private static readonly JsonSerializerOptions OPTIONS = new() { Converters = { new ScoreTableJsonConverter() } };
|
||||
|
||||
public static ScoreTable LoadOrCreate(string parPath)
|
||||
{
|
||||
ScoreTable? table = null;
|
||||
@@ -26,10 +26,12 @@ public class ScoreTable
|
||||
}
|
||||
|
||||
if (table != null)
|
||||
{
|
||||
return table;
|
||||
}
|
||||
|
||||
table = new ScoreTable();
|
||||
ScoreTable.Save(table, parPath);
|
||||
Save(table, parPath);
|
||||
|
||||
return table;
|
||||
}
|
||||
@@ -51,7 +53,9 @@ public class ScoreTableJsonConverter : JsonConverter<ScoreTable>
|
||||
{
|
||||
var rows = JsonSerializer.Deserialize<ScoreRow[]>(ref parReader, parOptions);
|
||||
if (rows == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var scoreTable = new ScoreTable();
|
||||
foreach (var row in rows)
|
||||
|
||||
@@ -138,7 +138,9 @@ public static class UiUtil
|
||||
StackComponent parStackComponent, RenderLayer? parRenderLayer = null)
|
||||
{
|
||||
foreach (var child in parStackComponent.Children)
|
||||
{
|
||||
child.Container = parStackComponent;
|
||||
}
|
||||
|
||||
var stackObject = new GameObject { Transform = { Translation = new Vector3(0, 0, -1) } };
|
||||
stackObject.AddComponent(parStackComponent);
|
||||
|
||||
Reference in New Issue
Block a user