This commit is contained in:
2025-01-07 23:28:49 +03:00
parent 10231492a6
commit 0cd2d8ea96
12 changed files with 202 additions and 107 deletions

View File

@@ -32,7 +32,7 @@ public class HealthController : Engine.Scene.Component.Component
/// Initializes a new instance of the <see cref="HealthController"/> class with an optional starting health value. /// Initializes a new instance of the <see cref="HealthController"/> class with an optional starting health value.
/// </summary> /// </summary>
/// <param name="parHealth">Initial health value. Defaults to 100.</param> /// <param name="parHealth">Initial health value. Defaults to 100.</param>
public HealthController(float parHealth = 100) public HealthController(float parHealth)
{ {
_healthModel = new HealthModel(parHealth); _healthModel = new HealthModel(parHealth);
} }

View File

@@ -0,0 +1,80 @@
namespace DoomDeathmatch.Scene;
public static class GameConstants
{
#region Enemies
#region Demon
public const int DEMON_BASE_SCORE = 50;
public const float DEMON_BASE_HEALTH = 150;
public const float DEMON_BASE_SPEED = 8;
public const float DEMON_FOLLOW_RADIUS = 1.5f;
public const float DEMON_CLOSE_COOLDOWN_ATTACK_RADIUS = 1.75f;
public const float DEMON_CLOSE_COOLDOWN_ATTACK_COOLDOWN = 1.75f;
public const float DEMON_CLOSE_COOLDOWN_ATTACK_DAMAGE = 10f;
public const int IMP_BASE_SCORE = 200;
public const float IMP_BASE_HEALTH = 300;
public const float IMP_BASE_SPEED = 7;
public const float IMP_FOLLOW_RADIUS = 10f;
#endregion
#region Imp
public const float IMP_CLOSE_CONTINUOUS_ATTACK_RADIUS = 1.75f;
public const float IMP_CLOSE_CONTINUOUS_ATTACK_DAMAGE = 10f;
public const float IMP_FIREBALL_ATTACK_COOLDOWN = 4f;
public const float IMP_FIREBALL_ATTACK_DAMAGE = 35f;
public const float IMP_FIREBALL_ATTACK_SPEED = 25f;
public const float IMP_FIREBALL_ATTACK_SIZE = 0.5f;
#endregion
public const int ENEMY_DEMON_SPAWN_WEIGHT = 6;
public const int ENEMY_IMP_SPAWN_WEIGHT = 4;
public const float ENEMY_SPAWN_RATE_SECONDS = 2f;
#endregion
#region Weapons
#region Pistol
public const int PISTOL_MAX_AMMO = 30;
public const int PISTOL_BASE_DAMAGE = 30;
#endregion
#region Shotgun
public const int SHOTGUN_MAX_AMMO = 10;
public const int SHOTGUN_BASE_DAMAGE = 5;
public const float SHOTGUN_SHOOT_PATTERN_ANGLE_DEGREES = 10f;
public const uint SHOTGUN_SHOOT_PATTERN_COUNT = 40;
#endregion
#endregion
#region Player
public const float PLAYER_BASE_HEALTH = 100;
public const float PLAYER_BASE_SPEED = 10;
#endregion
#region Consumables
public const int CONSUMABLE_HEALTH_PACK_SPAWN_WEIGHT = 2;
public const int CONSUMABLE_WEAPON_PISTOL_SPAWN_WEIGHT = 4;
public const int CONSUMABLE_WEAPON_SHOTGUN_SPAWN_WEIGHT = 3;
public const float CONSUMABLE_SPAWN_RATE_SECONDS = 5f;
public const float HEALTH_PACK_BASE_HEALING = 75f;
#endregion
}

View File

@@ -14,20 +14,20 @@ public static class GameOverScene
{ {
var scene = new Engine.Scene.Scene(); var scene = new Engine.Scene.Scene();
var (cameraObject, camera) = UiUtil.CreateOrthographicCamera(scene); var (cameraObject, camera) = UiPrefabs.CreateOrthographicCamera(scene);
var (uiContainerObject, uiContainer) = var (uiContainerObject, uiContainer) =
UiUtil.CreateBackgroundUi(scene, new UiContainerComponent { Camera = camera }); UiPrefabs.CreateBackgroundUi(scene, new UiContainerComponent { Camera = camera });
var (logoObject, logoUi) = UiUtil.CreateLogoUi(scene, uiContainer); var (logoObject, logoUi) = UiPrefabs.CreateLogoUi(scene, uiContainer);
logoUi.Offset = new Vector2(0, 3f); logoUi.Offset = new Vector2(0, 3f);
scene.AddChild(uiContainerObject, logoObject); scene.AddChild(uiContainerObject, logoObject);
var (resultUiObject, resultUi, _) = var (resultUiObject, resultUi, _) =
UiUtil.CreateTextUi(scene, uiContainer, UiUtil.GetDoomFont(), $"Ваш результат: {parScore}"); UiPrefabs.CreateTextUi(scene, uiContainer, UiPrefabs.GetDoomFont(), $"Ваш результат: {parScore}");
var (nameUiObject, nameUi, (_, nameTextRenderer)) = var (nameUiObject, nameUi, (_, nameTextRenderer)) =
UiUtil.CreateTextUi(scene, uiContainer, UiUtil.GetDoomFont(), "Имя: "); UiPrefabs.CreateTextUi(scene, uiContainer, UiPrefabs.GetDoomFont(), "Имя: ");
var nameInputComponent = new TextInputComponent { IsActive = true }; var nameInputComponent = new TextInputComponent { IsActive = true };
nameInputComponent.OnInput += parName => nameInputComponent.OnInput += parName =>
@@ -37,7 +37,7 @@ public static class GameOverScene
nameUiObject.AddComponent(nameInputComponent); nameUiObject.AddComponent(nameInputComponent);
var (nextUiObject, nextUi, _) = var (nextUiObject, nextUi, _) =
UiUtil.CreateTextUi(scene, uiContainer, UiUtil.GetDoomFont(), "Далее"); UiPrefabs.CreateTextUi(scene, uiContainer, UiPrefabs.GetDoomFont(), "Далее");
nextUi.OnClick += _ => nextUi.OnClick += _ =>
{ {
if (string.IsNullOrEmpty(nameInputComponent.Input)) if (string.IsNullOrEmpty(nameInputComponent.Input))
@@ -49,10 +49,10 @@ public static class GameOverScene
EngineUtil.SceneManager.TransitionTo(MainScene.Create); EngineUtil.SceneManager.TransitionTo(MainScene.Create);
}; };
var (selectorObject, selector) = UiUtil.CreateSelectorUi(scene, var (selectorObject, selector) = UiPrefabs.CreateSelectorUi(scene,
new SelectorComponent { Children = { nextUi }, SelectKey = KeyboardButtonCode.Enter }, RenderLayer.HUD); new SelectorComponent { Children = { nextUi }, SelectKey = KeyboardButtonCode.Enter }, RenderLayer.HUD);
var (stackObject, stack) = UiUtil.CreateStackUi(scene, var (stackObject, stack) = UiPrefabs.CreateStackUi(scene,
new StackComponent { Offset = new Vector2(0, -1f), Container = uiContainer, Children = { resultUi, nextUi } }); new StackComponent { Offset = new Vector2(0, -1f), Container = uiContainer, Children = { resultUi, nextUi } });
stackObject.Transform.Size.Xy = new Vector2(1f, 6f); stackObject.Transform.Size.Xy = new Vector2(1f, 6f);

View File

@@ -15,12 +15,12 @@ public static class MainScene
{ {
var scene = new Engine.Scene.Scene(); var scene = new Engine.Scene.Scene();
var (cameraObject, camera) = UiUtil.CreateOrthographicCamera(scene); var (cameraObject, camera) = UiPrefabs.CreateOrthographicCamera(scene);
var (uiContainerObject, uiContainer) = var (uiContainerObject, uiContainer) =
UiUtil.CreateBackgroundUi(scene, new UiContainerComponent { Camera = camera }); UiPrefabs.CreateBackgroundUi(scene, new UiContainerComponent { Camera = camera });
var (logoObject, logoUi) = UiUtil.CreateLogoUi(scene, uiContainer); var (logoObject, logoUi) = UiPrefabs.CreateLogoUi(scene, uiContainer);
logoUi.Offset = new Vector2(0, 3f); logoUi.Offset = new Vector2(0, 3f);
scene.AddChild(uiContainerObject, logoObject); scene.AddChild(uiContainerObject, logoObject);
@@ -53,18 +53,18 @@ public static class MainScene
var parentObject = GameObjectUtil.CreateGameObject(parScene); var parentObject = GameObjectUtil.CreateGameObject(parScene);
var (playUiObject, playUi, _) = var (playUiObject, playUi, _) =
UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(), "Играть"); UiPrefabs.CreateTextUi(parScene, parUiContainer, UiPrefabs.GetDoomFont(), "Играть");
var (leadersUiObject, leadersUi, _) = var (leadersUiObject, leadersUi, _) =
UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(), "Лидеры"); UiPrefabs.CreateTextUi(parScene, parUiContainer, UiPrefabs.GetDoomFont(), "Лидеры");
var (rulesUiObject, rulesUi, _) = var (rulesUiObject, rulesUi, _) =
UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(), "Правила"); UiPrefabs.CreateTextUi(parScene, parUiContainer, UiPrefabs.GetDoomFont(), "Правила");
var (exitUiObject, exitUi, _) = var (exitUiObject, exitUi, _) =
UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(), "Выход"); UiPrefabs.CreateTextUi(parScene, parUiContainer, UiPrefabs.GetDoomFont(), "Выход");
var (stackObject, stack) = UiUtil.CreateStackUi(parScene, var (stackObject, stack) = UiPrefabs.CreateStackUi(parScene,
new StackComponent new StackComponent
{ {
Offset = new Vector2(0, -1f), Container = parUiContainer, Children = { playUi, leadersUi, rulesUi, exitUi } Offset = new Vector2(0, -1f), Container = parUiContainer, Children = { playUi, leadersUi, rulesUi, exitUi }
@@ -76,7 +76,7 @@ public static class MainScene
rulesUi.OnClick += _ => parMenuController.SelectMenuItem("rules"); rulesUi.OnClick += _ => parMenuController.SelectMenuItem("rules");
exitUi.OnClick += _ => EngineUtil.Close(); exitUi.OnClick += _ => EngineUtil.Close();
var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene, var (selectorObject, selector) = UiPrefabs.CreateSelectorUi(parScene,
new SelectorComponent { Children = { playUi, leadersUi, rulesUi, exitUi } }); new SelectorComponent { Children = { playUi, leadersUi, rulesUi, exitUi } });
parScene.AddChild(parentObject, selectorObject); parScene.AddChild(parentObject, selectorObject);
@@ -95,11 +95,11 @@ public static class MainScene
{ {
var parentObject = GameObjectUtil.CreateGameObject(parScene); var parentObject = GameObjectUtil.CreateGameObject(parScene);
var (backUiObject, backUi, _) = UiUtil.CreateTextUi(parScene, parUiContainer, var (backUiObject, backUi, _) = UiPrefabs.CreateTextUi(parScene, parUiContainer,
UiUtil.GetDoomFont(), "Назад"); UiPrefabs.GetDoomFont(), "Назад");
backUi.OnClick += _ => parMenuController.SelectMenuItem("main"); backUi.OnClick += _ => parMenuController.SelectMenuItem("main");
var (stackObject, stack) = UiUtil.CreateStackUi(parScene, var (stackObject, stack) = UiPrefabs.CreateStackUi(parScene,
new StackComponent { Offset = new Vector2(0, -1.5f), Container = parUiContainer }); new StackComponent { Offset = new Vector2(0, -1.5f), Container = parUiContainer });
stackObject.Transform.Size.Xy = new Vector2(1f, 6f); stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
@@ -112,7 +112,7 @@ public static class MainScene
stack.Children.Add(backUi); stack.Children.Add(backUi);
var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene, new SelectorComponent { Children = { backUi } }); var (selectorObject, selector) = UiPrefabs.CreateSelectorUi(parScene, new SelectorComponent { Children = { backUi } });
parScene.AddChild(parentObject, selectorObject); parScene.AddChild(parentObject, selectorObject);
parScene.AddChild(parentObject, stackObject); parScene.AddChild(parentObject, stackObject);
@@ -153,12 +153,12 @@ public static class MainScene
]); ]);
var (nameUiObject, nameUi, _) = var (nameUiObject, nameUi, _) =
UiUtil.CreateTextUi(parScene, uiComponent, UiUtil.GetDoomFont(), parName); UiPrefabs.CreateTextUi(parScene, uiComponent, UiPrefabs.GetDoomFont(), parName);
nameUi.Anchor = Anchor.CenterLeft; nameUi.Anchor = Anchor.CenterLeft;
nameUi.Center = Anchor.Center; nameUi.Center = Anchor.Center;
var (scoreUiObject, scoreUi, _) = var (scoreUiObject, scoreUi, _) =
UiUtil.CreateTextUi(parScene, uiComponent, UiUtil.GetDoomFont(), parScore); UiPrefabs.CreateTextUi(parScene, uiComponent, UiPrefabs.GetDoomFont(), parScore);
scoreUi.Anchor = Anchor.CenterRight; scoreUi.Anchor = Anchor.CenterRight;
scoreUi.Center = Anchor.Center; scoreUi.Center = Anchor.Center;
@@ -173,18 +173,18 @@ public static class MainScene
{ {
var parentObject = GameObjectUtil.CreateGameObject(parScene); var parentObject = GameObjectUtil.CreateGameObject(parScene);
var (backUiObject, backUi, _) = UiUtil.CreateTextUi(parScene, parUiContainer, var (backUiObject, backUi, _) = UiPrefabs.CreateTextUi(parScene, parUiContainer,
UiUtil.GetDoomFont(), "Назад"); UiPrefabs.GetDoomFont(), "Назад");
backUi.OnClick += _ => parMenuController.SelectMenuItem("main"); backUi.OnClick += _ => parMenuController.SelectMenuItem("main");
var (rulesObject, rulesUi, _) = UiUtil.CreateTextUi(parScene, parUiContainer, var (rulesObject, rulesUi, _) = UiPrefabs.CreateTextUi(parScene, parUiContainer,
UiUtil.GetDoomFont(), "Правила"); UiPrefabs.GetDoomFont(), "Правила");
var (stackObject, stack) = UiUtil.CreateStackUi(parScene, var (stackObject, stack) = UiPrefabs.CreateStackUi(parScene,
new StackComponent { Offset = new Vector2(0, -1f), Container = parUiContainer, Children = { rulesUi, backUi } }); new StackComponent { Offset = new Vector2(0, -1f), Container = parUiContainer, Children = { rulesUi, backUi } });
stackObject.Transform.Size.Xy = new Vector2(1f, 6f); stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene, new SelectorComponent { Children = { backUi } }); var (selectorObject, selector) = UiPrefabs.CreateSelectorUi(parScene, new SelectorComponent { Children = { backUi } });
parScene.AddChild(parentObject, selectorObject); parScene.AddChild(parentObject, selectorObject);

View File

@@ -33,9 +33,9 @@ public static class PlayScene
{ {
var scene = new Engine.Scene.Scene(); var scene = new Engine.Scene.Scene();
var (hudCameraObject, hudCamera) = UiUtil.CreateOrthographicCamera(scene, RenderLayer.HUD); var (hudCameraObject, hudCamera) = UiPrefabs.CreateOrthographicCamera(scene, RenderLayer.HUD);
var (uiContainerObject, uiContainer) = var (uiContainerObject, uiContainer) =
UiUtil.CreateContainerUi(scene, new UiContainerComponent { Camera = hudCamera }); UiPrefabs.CreateContainerUi(scene, new UiContainerComponent { Camera = hudCamera });
var menuController = new MenuControllerComponent(); var menuController = new MenuControllerComponent();
var menuControllerObject = GameObjectUtil.CreateGameObject(scene, [ var menuControllerObject = GameObjectUtil.CreateGameObject(scene, [
@@ -100,14 +100,14 @@ public static class PlayScene
new ObjectSpawner(new WeightedRandomValueProvider<GameObject>( new ObjectSpawner(new WeightedRandomValueProvider<GameObject>(
new List<(int, IValueProvider<GameObject>)> new List<(int, IValueProvider<GameObject>)>
{ {
(6, GeneratorValueProvider<GameObject>.Create(() => (GameConstants.ENEMY_DEMON_SPAWN_WEIGHT, GeneratorValueProvider<GameObject>.Create(() =>
EnemyPrefab.Create(EngineUtil.SceneManager.CurrentScene!, EnemyData.Demon))), EnemyPrefab.Create(EngineUtil.SceneManager.CurrentScene!, EnemyData.Demon))),
(4, (GameConstants.ENEMY_IMP_SPAWN_WEIGHT,
GeneratorValueProvider<GameObject>.Create(() => GeneratorValueProvider<GameObject>.Create(() =>
EnemyPrefab.Create(EngineUtil.SceneManager.CurrentScene!, EnemyData.Imp))) EnemyPrefab.Create(EngineUtil.SceneManager.CurrentScene!, EnemyData.Imp)))
}), }),
monsterVector3ValueProvider, monsterVector3ValueProvider,
new TickableTimerCondition(2f))) new TickableTimerCondition(GameConstants.ENEMY_SPAWN_RATE_SECONDS)))
] ]
); );
@@ -127,16 +127,16 @@ public static class PlayScene
new ObjectSpawner(new WeightedRandomValueProvider<GameObject>( new ObjectSpawner(new WeightedRandomValueProvider<GameObject>(
new List<(int, IValueProvider<GameObject>)> new List<(int, IValueProvider<GameObject>)>
{ {
(2, GeneratorValueProvider<GameObject>.Create(() => (GameConstants.CONSUMABLE_HEALTH_PACK_SPAWN_WEIGHT, GeneratorValueProvider<GameObject>.Create(() =>
{ {
var gameController = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<GameController>()!; var gameController = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<GameController>()!;
return ConsumablePrefab.Create(EngineUtil.SceneManager.CurrentScene, return ConsumablePrefab.Create(EngineUtil.SceneManager.CurrentScene,
new HealthPackConsumable(75), new HealthPackConsumable(GameConstants.HEALTH_PACK_BASE_HEALING),
gameController.PlayerController.Camera.GameObject.Transform gameController.PlayerController.Camera.GameObject.Transform
); );
})), })),
(4, GeneratorValueProvider<GameObject>.Create(() => (GameConstants.CONSUMABLE_WEAPON_PISTOL_SPAWN_WEIGHT, GeneratorValueProvider<GameObject>.Create(() =>
{ {
var gameController = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<GameController>()!; var gameController = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<GameController>()!;
@@ -145,7 +145,7 @@ public static class PlayScene
gameController.PlayerController.Camera.GameObject.Transform gameController.PlayerController.Camera.GameObject.Transform
); );
})), })),
(3, GeneratorValueProvider<GameObject>.Create(() => (GameConstants.CONSUMABLE_WEAPON_SHOTGUN_SPAWN_WEIGHT, GeneratorValueProvider<GameObject>.Create(() =>
{ {
var gameController = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<GameController>()!; var gameController = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<GameController>()!;
@@ -156,7 +156,7 @@ public static class PlayScene
})) }))
}), }),
consumableVector3ValueProvider, consumableVector3ValueProvider,
new TickableTimerCondition(5f))) new TickableTimerCondition(GameConstants.CONSUMABLE_SPAWN_RATE_SECONDS)))
] ]
); );
@@ -216,7 +216,7 @@ public static class PlayScene
var parentObject = GameObjectUtil.CreateGameObject(parScene); var parentObject = GameObjectUtil.CreateGameObject(parScene);
var (bottomContainerObject, bottomContainer) = var (bottomContainerObject, bottomContainer) =
UiUtil.CreateContainerUi(parScene, new UiContainerComponent { Container = parUiContainer }); UiPrefabs.CreateContainerUi(parScene, new UiContainerComponent { Container = parUiContainer });
bottomContainer.Anchor = Anchor.BottomCenter; bottomContainer.Anchor = Anchor.BottomCenter;
bottomContainer.Center = Anchor.BottomCenter; bottomContainer.Center = Anchor.BottomCenter;
bottomContainerObject.AddComponent(new Box2DRenderer bottomContainerObject.AddComponent(new Box2DRenderer
@@ -230,7 +230,7 @@ public static class PlayScene
bottomContainerObject.Transform.Size.Y = 1.5f; bottomContainerObject.Transform.Size.Y = 1.5f;
parScene.AddChild(parentObject, bottomContainerObject); parScene.AddChild(parentObject, bottomContainerObject);
var (gunObject, (gunUi, gunSprite)) = UiUtil.CreateSpriteUi(parScene, bottomContainer, var (gunObject, (gunUi, gunSprite)) = UiPrefabs.CreateSpriteUi(parScene, bottomContainer,
null, RenderLayer.HUD); null, RenderLayer.HUD);
gunObject.Transform.Scale = new Vector3(5); gunObject.Transform.Scale = new Vector3(5);
gunUi.Anchor = Anchor.TopCenter; gunUi.Anchor = Anchor.TopCenter;
@@ -239,7 +239,7 @@ public static class PlayScene
parScene.AddChild(bottomContainerObject, gunObject); parScene.AddChild(bottomContainerObject, gunObject);
var (healthObject, healthUi, (_, healthTextRenderer)) = var (healthObject, healthUi, (_, healthTextRenderer)) =
UiUtil.CreateTextUi(parScene, bottomContainer, UiUtil.GetDoomFont(), "Здоровье: 000", UiPrefabs.CreateTextUi(parScene, bottomContainer, UiPrefabs.GetDoomFont(), "Здоровье: 000",
Align.Center, Align.Center,
RenderLayer.HUD); RenderLayer.HUD);
healthObject.Transform.Scale = new Vector3(0.75f); healthObject.Transform.Scale = new Vector3(0.75f);
@@ -248,7 +248,7 @@ public static class PlayScene
parScene.AddChild(bottomContainerObject, healthObject); parScene.AddChild(bottomContainerObject, healthObject);
var (ammoObject, ammoUi, (_, ammoTextRenderer)) = var (ammoObject, ammoUi, (_, ammoTextRenderer)) =
UiUtil.CreateTextUi(parScene, bottomContainer, UiUtil.GetDoomFont(), "Патроны: 00/00", UiPrefabs.CreateTextUi(parScene, bottomContainer, UiPrefabs.GetDoomFont(), "Патроны: 00/00",
Align.Center, Align.Center,
RenderLayer.HUD); RenderLayer.HUD);
ammoObject.Transform.Scale = new Vector3(0.75f); ammoObject.Transform.Scale = new Vector3(0.75f);
@@ -257,7 +257,7 @@ public static class PlayScene
parScene.AddChild(bottomContainerObject, ammoObject); parScene.AddChild(bottomContainerObject, ammoObject);
var (weaponObject, weaponUi, (_, weaponTextRenderer)) = var (weaponObject, weaponUi, (_, weaponTextRenderer)) =
UiUtil.CreateTextUi(parScene, bottomContainer, UiUtil.GetDoomFont(), "Оружие: ОРУЖИЕОР", UiPrefabs.CreateTextUi(parScene, bottomContainer, UiPrefabs.GetDoomFont(), "Оружие: ОРУЖИЕОР",
Align.Center, Align.Center,
RenderLayer.HUD); RenderLayer.HUD);
weaponObject.Transform.Scale = new Vector3(0.75f); weaponObject.Transform.Scale = new Vector3(0.75f);
@@ -266,7 +266,7 @@ public static class PlayScene
parScene.AddChild(bottomContainerObject, weaponObject); parScene.AddChild(bottomContainerObject, weaponObject);
var (topContainerObject, topContainer) = var (topContainerObject, topContainer) =
UiUtil.CreateContainerUi(parScene, new UiContainerComponent { Container = parUiContainer }); UiPrefabs.CreateContainerUi(parScene, new UiContainerComponent { Container = parUiContainer });
topContainer.Anchor = Anchor.TopCenter; topContainer.Anchor = Anchor.TopCenter;
topContainer.Center = Anchor.TopCenter; topContainer.Center = Anchor.TopCenter;
topContainerObject.AddComponent( topContainerObject.AddComponent(
@@ -279,14 +279,14 @@ public static class PlayScene
parScene.AddChild(parentObject, topContainerObject); parScene.AddChild(parentObject, topContainerObject);
var (timerObject, timerUi, (_, timerTextRenderer)) = var (timerObject, timerUi, (_, timerTextRenderer)) =
UiUtil.CreateTextUi(parScene, topContainer, UiUtil.GetDoomFont(), "Время: 00:00", UiPrefabs.CreateTextUi(parScene, topContainer, UiPrefabs.GetDoomFont(), "Время: 00:00",
parRenderLayer: RenderLayer.HUD); parRenderLayer: RenderLayer.HUD);
timerUi.Anchor = Anchor.CenterLeft; timerUi.Anchor = Anchor.CenterLeft;
timerUi.Center = Anchor.CenterLeft; timerUi.Center = Anchor.CenterLeft;
parScene.AddChild(topContainerObject, timerObject); parScene.AddChild(topContainerObject, timerObject);
var (scoreObject, scoreUi, (_, scoreTextRenderer)) = var (scoreObject, scoreUi, (_, scoreTextRenderer)) =
UiUtil.CreateTextUi(parScene, topContainer, UiUtil.GetDoomFont(), "Счет: 00000", UiPrefabs.CreateTextUi(parScene, topContainer, UiPrefabs.GetDoomFont(), "Счет: 00000",
parRenderLayer: RenderLayer.HUD); parRenderLayer: RenderLayer.HUD);
scoreUi.Anchor = Anchor.CenterRight; scoreUi.Anchor = Anchor.CenterRight;
scoreUi.Center = Anchor.CenterRight; scoreUi.Center = Anchor.CenterRight;
@@ -305,34 +305,34 @@ public static class PlayScene
{ {
var parentObject = GameObjectUtil.CreateGameObject(parScene); var parentObject = GameObjectUtil.CreateGameObject(parScene);
var (backgroundObject, backgroundUiContainer) = UiUtil.CreateBackgroundUi(parScene, var (backgroundObject, backgroundUiContainer) = UiPrefabs.CreateBackgroundUi(parScene,
new UiContainerComponent { Container = parUiContainer }, new Vector4(0, 0, 0, 0.9f), RenderLayer.HUD); new UiContainerComponent { Container = parUiContainer }, new Vector4(0, 0, 0, 0.9f), RenderLayer.HUD);
backgroundObject.AddComponent(new CopySizeComponent { Target = parUiContainer.GameObject.Transform }); backgroundObject.AddComponent(new CopySizeComponent { Target = parUiContainer.GameObject.Transform });
parScene.AddChild(parentObject, backgroundObject); parScene.AddChild(parentObject, backgroundObject);
var (logoObject, logoUi) = UiUtil.CreateLogoUi(parScene, backgroundUiContainer, RenderLayer.HUD); var (logoObject, logoUi) = UiPrefabs.CreateLogoUi(parScene, backgroundUiContainer, RenderLayer.HUD);
logoUi.Offset = new Vector2(0, 3f); logoUi.Offset = new Vector2(0, 3f);
parScene.AddChild(parentObject, logoObject); parScene.AddChild(parentObject, logoObject);
var (backUiObject, backUi, _) = UiUtil.CreateTextUi(parScene, backgroundUiContainer, var (backUiObject, backUi, _) = UiPrefabs.CreateTextUi(parScene, backgroundUiContainer,
UiUtil.GetDoomFont(), "Назад", UiPrefabs.GetDoomFont(), "Назад",
parRenderLayer: RenderLayer.HUD); parRenderLayer: RenderLayer.HUD);
backUi.OnClick += _ => backUi.OnClick += _ =>
EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<GameController>()!.Unpause(); EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<GameController>()!.Unpause();
var (exitUiObject, exitUi, _) = UiUtil.CreateTextUi(parScene, backgroundUiContainer, var (exitUiObject, exitUi, _) = UiPrefabs.CreateTextUi(parScene, backgroundUiContainer,
UiUtil.GetDoomFont(), "Выход", UiPrefabs.GetDoomFont(), "Выход",
parRenderLayer: RenderLayer.HUD); parRenderLayer: RenderLayer.HUD);
exitUi.OnClick += _ => EngineUtil.SceneManager.TransitionTo(MainScene.Create); exitUi.OnClick += _ => EngineUtil.SceneManager.TransitionTo(MainScene.Create);
var (stackObject, stack) = UiUtil.CreateStackUi(parScene, var (stackObject, stack) = UiPrefabs.CreateStackUi(parScene,
new StackComponent new StackComponent
{ {
Offset = new Vector2(0, -1f), Container = backgroundUiContainer, Children = { backUi, exitUi } Offset = new Vector2(0, -1f), Container = backgroundUiContainer, Children = { backUi, exitUi }
}); });
stackObject.Transform.Size.Xy = new Vector2(1f, 6f); stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene, var (selectorObject, selector) = UiPrefabs.CreateSelectorUi(parScene,
new SelectorComponent { Children = { backUi, exitUi } }, RenderLayer.HUD); new SelectorComponent { Children = { backUi, exitUi } }, RenderLayer.HUD);
parScene.AddChild(parentObject, selectorObject); parScene.AddChild(parentObject, selectorObject);

View File

@@ -21,7 +21,7 @@ public static class EnemyPrefab
{ {
public static GameObject Create(Engine.Scene.Scene parScene, EnemyData parEnemyData) public static GameObject Create(Engine.Scene.Scene parScene, EnemyData parEnemyData)
{ {
var enemyHealthTextRenderer = new TextRenderer { Font = UiUtil.GetDoomFont(), Text = "Здоровье: 000" }; var enemyHealthTextRenderer = new TextRenderer { Font = UiPrefabs.GetDoomFont(), Text = "Здоровье: 000" };
var enemyBox2DRenderer = new Box2DRenderer(); var enemyBox2DRenderer = new Box2DRenderer();
var enemyObject = GameObjectUtil.CreateGameObject(parScene, var enemyObject = GameObjectUtil.CreateGameObject(parScene,
@@ -69,13 +69,13 @@ public static class EnemyPrefab
} }
public static GameObject CreateFireball(Engine.Scene.Scene parScene, Vector3 parPosition, public static GameObject CreateFireball(Engine.Scene.Scene parScene, Vector3 parPosition,
Vector3 parVelocity, float parDamage, Transform? parBillboardTarget = null) Vector3 parVelocity, float parSize, float parDamage, Transform? parBillboardTarget = null)
{ {
var rigidbodyComponent = new RigidbodyComponent(); var rigidbodyComponent = new RigidbodyComponent();
rigidbodyComponent.Velocity += parVelocity; rigidbodyComponent.Velocity += parVelocity;
var fireballObject = GameObjectUtil.CreateGameObject(parScene, var fireballObject = GameObjectUtil.CreateGameObject(parScene,
new Transform { Translation = parPosition, Size = new Vector3(0.5f) }, new Transform { Translation = parPosition, Size = new Vector3(parSize) },
[ [
rigidbodyComponent, rigidbodyComponent,
new Box2DRenderer { Texture = EngineUtil.AssetResourceManager.Load<Texture>("texture/fireball.png") }, new Box2DRenderer { Texture = EngineUtil.AssetResourceManager.Load<Texture>("texture/fireball.png") },
@@ -83,7 +83,7 @@ public static class EnemyPrefab
new FireballComponent { Damage = parDamage }, new FireballComponent { Damage = parDamage },
new AABBColliderComponent new AABBColliderComponent
{ {
Collider = new AABBCollider { Size = new Vector3(0.25f) }, Collider = new AABBCollider { Size = new Vector3(parSize) },
ColliderGroups = { "fireball" }, ColliderGroups = { "fireball" },
ExcludeColliderCollideGroups = { "enemy", "fireball", "consumable" } ExcludeColliderCollideGroups = { "enemy", "fireball", "consumable" }
} }

View File

@@ -14,12 +14,12 @@ public static class PlayerPrefab
{ {
public static GameObject Create(Engine.Scene.Scene parScene, WeaponView parWeaponView, HealthView parHealthView) public static GameObject Create(Engine.Scene.Scene parScene, WeaponView parWeaponView, HealthView parHealthView)
{ {
var (perspectiveCameraObject, perspectiveCamera) = UiUtil.CreatePerspectiveCamera(parScene); var (perspectiveCameraObject, perspectiveCamera) = UiPrefabs.CreatePerspectiveCamera(parScene);
perspectiveCameraObject.Transform.Translation.Z = 2; perspectiveCameraObject.Transform.Translation.Z = 2;
var playerObject = GameObjectUtil.CreateGameObject(parScene, [ var playerObject = GameObjectUtil.CreateGameObject(parScene, [
new PlayerMovementComponent(), new PlayerMovementComponent(),
new MovementController { Speed = 10f }, new MovementController { Speed = GameConstants.PLAYER_BASE_SPEED },
new RigidbodyComponent(), new RigidbodyComponent(),
new DragComponent { Drag = 10f, Multiplier = new Vector3(1, 1, 0) }, new DragComponent { Drag = 10f, Multiplier = new Vector3(1, 1, 0) },
@@ -36,7 +36,7 @@ public static class PlayerPrefab
new WeaponController(), new WeaponController(),
parWeaponView, parWeaponView,
new HealthController(), new HealthController(GameConstants.PLAYER_BASE_HEALTH),
parHealthView parHealthView
]); ]);

View File

@@ -9,9 +9,9 @@ using Engine.Scene.Component.BuiltIn.Renderer;
using Engine.Util; using Engine.Util;
using OpenTK.Mathematics; using OpenTK.Mathematics;
namespace DoomDeathmatch; namespace DoomDeathmatch.Scene;
public static class UiUtil public static class UiPrefabs
{ {
public static Font GetDoomFont() public static Font GetDoomFont()
{ {
@@ -52,10 +52,10 @@ public static class UiUtil
}; };
var uiComponent = new UiContainerComponent { Container = parContainer }; var uiComponent = new UiContainerComponent { Container = parContainer };
outerObject.AddComponent(uiComponent); outerObject.AddComponent(uiComponent);
outerObject.AddComponent(new Box2DRenderer // outerObject.AddComponent(new Box2DRenderer
{ // {
Color = new Vector4(0, 0, 1, 1), RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT // Color = new Vector4(0, 0, 1, 1), RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT
}); // });
var innerObject = new GameObject { Transform = { Translation = new Vector3(0, 0, -1) } }; var innerObject = new GameObject { Transform = { Translation = new Vector3(0, 0, -1) } };
// var innerUiComponent = new UiComponent { Container = uiComponent }; // var innerUiComponent = new UiComponent { Container = uiComponent };

View File

@@ -1,5 +1,6 @@
using DoomDeathmatch.Component.MVC.Enemy; using DoomDeathmatch.Component.MVC.Enemy;
using DoomDeathmatch.Component.MVC.Health; using DoomDeathmatch.Component.MVC.Health;
using DoomDeathmatch.Script.Provider;
using Engine.Scene; using Engine.Scene;
using Engine.Util; using Engine.Util;
@@ -13,7 +14,7 @@ public class ObjectSpawnAttackBehavior : CooldownAttackBehavior
/// <summary> /// <summary>
/// The function used to spawn an object based on the enemy and target controllers. /// The function used to spawn an object based on the enemy and target controllers.
/// </summary> /// </summary>
private readonly Func<EnemyController, HealthController, GameObject> _objectSpawnFunc; private readonly IValueProvider<GameObject> _objectValueProvider;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ObjectSpawnAttackBehavior"/> class. /// Initializes a new instance of the <see cref="ObjectSpawnAttackBehavior"/> class.
@@ -21,14 +22,14 @@ public class ObjectSpawnAttackBehavior : CooldownAttackBehavior
/// <param name="parEnemyController">The enemy controller.</param> /// <param name="parEnemyController">The enemy controller.</param>
/// <param name="parHealthController">The health controller of the target.</param> /// <param name="parHealthController">The health controller of the target.</param>
/// <param name="parCooldown">The cooldown duration between spawns.</param> /// <param name="parCooldown">The cooldown duration between spawns.</param>
/// <param name="parObjectSpawnFunc">The function used to create the spawned object.</param> /// <param name="parObjectValueProvider">The function used to create the spawned object.</param>
public ObjectSpawnAttackBehavior(EnemyController parEnemyController, public ObjectSpawnAttackBehavior(EnemyController parEnemyController,
HealthController parHealthController, HealthController parHealthController,
float parCooldown, float parCooldown,
Func<EnemyController, HealthController, GameObject> parObjectSpawnFunc) : base(parEnemyController, IValueProvider<GameObject> parObjectValueProvider) : base(parEnemyController,
parHealthController, parCooldown) parHealthController, parCooldown)
{ {
_objectSpawnFunc = parObjectSpawnFunc; _objectValueProvider = parObjectValueProvider;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -40,7 +41,7 @@ public class ObjectSpawnAttackBehavior : CooldownAttackBehavior
/// <inheritdoc /> /// <inheritdoc />
protected override bool ActivateAttack() protected override bool ActivateAttack()
{ {
var enemyObject = _objectSpawnFunc(_enemyController, _healthController); var enemyObject = _objectValueProvider.GetValue();
EngineUtil.SceneManager.CurrentScene!.Add(enemyObject); EngineUtil.SceneManager.CurrentScene!.Add(enemyObject);
return true; return true;

View File

@@ -1,6 +1,9 @@
using DoomDeathmatch.Scene.Play.Prefab; using DoomDeathmatch.Scene;
using DoomDeathmatch.Scene.Play.Prefab;
using DoomDeathmatch.Script.Model.Enemy.Attack; using DoomDeathmatch.Script.Model.Enemy.Attack;
using DoomDeathmatch.Script.Model.Enemy.Movement; using DoomDeathmatch.Script.Model.Enemy.Movement;
using DoomDeathmatch.Script.Provider;
using Engine.Scene;
using Engine.Util; using Engine.Util;
using OpenTK.Mathematics; using OpenTK.Mathematics;
@@ -20,13 +23,16 @@ public class EnemyData
Id = "demon", Id = "demon",
Name = "Демон", Name = "Демон",
Texture = "texture/demon.png", Texture = "texture/demon.png",
BaseHealth = 150, BaseScore = GameConstants.DEMON_BASE_SCORE,
BaseScore = 50, BaseHealth = GameConstants.DEMON_BASE_HEALTH,
BaseSpeed = 8, BaseSpeed = GameConstants.DEMON_BASE_SPEED,
MovementBehavior = new FollowPlayerMovementBehavior(1.5f), MovementBehavior = new FollowPlayerMovementBehavior(GameConstants.DEMON_FOLLOW_RADIUS),
AttackBehaviorCreator = new FuncAttackBehaviorCreator( AttackBehaviorCreator = new FuncAttackBehaviorCreator(
(parEnemyController, parHealthController) => (parEnemyController, parHealthController) =>
new CloseCooldownAttackBehavior(parEnemyController, parHealthController, 1.75f, 2.5f, 10) new CloseCooldownAttackBehavior(parEnemyController, parHealthController,
GameConstants.DEMON_CLOSE_COOLDOWN_ATTACK_RADIUS,
GameConstants.DEMON_CLOSE_COOLDOWN_ATTACK_COOLDOWN,
GameConstants.DEMON_CLOSE_COOLDOWN_ATTACK_DAMAGE)
) )
}; };
@@ -39,31 +45,36 @@ public class EnemyData
Id = "imp", Id = "imp",
Name = "Имп", Name = "Имп",
Texture = "texture/imp.png", Texture = "texture/imp.png",
BaseHealth = 300, BaseScore = GameConstants.IMP_BASE_SCORE,
BaseScore = 200, BaseHealth = GameConstants.IMP_BASE_HEALTH,
BaseSpeed = 7, BaseSpeed = GameConstants.IMP_BASE_SPEED,
MovementBehavior = new FollowPlayerMovementBehavior(10f), MovementBehavior = new FollowPlayerMovementBehavior(GameConstants.IMP_FOLLOW_RADIUS),
AttackBehaviorCreator = new FuncAttackBehaviorCreator( AttackBehaviorCreator = new FuncAttackBehaviorCreator(
(parEnemyController, parHealthController) => (parEnemyController, parHealthController) =>
new CompositeAttackBehavior(parEnemyController, parHealthController, new CompositeAttackBehavior(parEnemyController, parHealthController,
[ [
new CloseContinuousAttackBehavior(parEnemyController, parHealthController, 1.75f, 10f), new CloseContinuousAttackBehavior(parEnemyController, parHealthController,
new ObjectSpawnAttackBehavior(parEnemyController, parHealthController, 4f, GameConstants.IMP_CLOSE_CONTINUOUS_ATTACK_RADIUS,
(parEnemyController, parHealthController) => GameConstants.IMP_CLOSE_CONTINUOUS_ATTACK_DAMAGE),
new ObjectSpawnAttackBehavior(parEnemyController, parHealthController,
GameConstants.IMP_FIREBALL_ATTACK_COOLDOWN,
GeneratorValueProvider<GameObject>.Create(() =>
{ {
var direction = var direction =
(parHealthController.GameObject.Transform.Translation - (parHealthController.GameObject.Transform.Translation -
parEnemyController.GameObject.Transform.Translation).Normalized(); parEnemyController.GameObject.Transform.Translation).Normalized();
var fireballObject = EnemyPrefab.CreateFireball(EngineUtil.SceneManager.CurrentScene!, var fireballObject = EnemyPrefab.CreateFireball(
EngineUtil.SceneManager.CurrentScene!,
parEnemyController.GameObject.Transform.Translation + new Vector3(0, 0f, 1.75f), parEnemyController.GameObject.Transform.Translation + new Vector3(0, 0f, 1.75f),
direction * 25, GameConstants.IMP_FIREBALL_ATTACK_SPEED * direction,
35, GameConstants.IMP_FIREBALL_ATTACK_SIZE,
GameConstants.IMP_FIREBALL_ATTACK_DAMAGE,
parHealthController.GameObject.Transform parHealthController.GameObject.Transform
); );
return fireballObject; return fireballObject;
} })
) )
] ]
) )
@@ -85,16 +96,16 @@ public class EnemyData
/// </summary> /// </summary>
public string Texture { get; private init; } = ""; public string Texture { get; private init; } = "";
/// <summary>
/// The base health of the enemy.
/// </summary>
public float BaseHealth { get; private init; }
/// <summary> /// <summary>
/// The base score awarded for defeating this enemy. /// The base score awarded for defeating this enemy.
/// </summary> /// </summary>
public int BaseScore { get; private init; } public int BaseScore { get; private init; }
/// <summary>
/// The base health of the enemy.
/// </summary>
public float BaseHealth { get; private init; }
/// <summary> /// <summary>
/// The base speed of the enemy. /// The base speed of the enemy.
/// </summary> /// </summary>

View File

@@ -1,4 +1,5 @@
using OpenTK.Mathematics; using DoomDeathmatch.Scene;
using OpenTK.Mathematics;
namespace DoomDeathmatch.Script.Model.Weapon; namespace DoomDeathmatch.Script.Model.Weapon;
@@ -11,17 +12,20 @@ public class WeaponData
/// Data for the "Pistol" weapon. /// Data for the "Pistol" weapon.
/// </summary> /// </summary>
public static WeaponData Pistol => public static WeaponData Pistol =>
new(30) new(GameConstants.PISTOL_MAX_AMMO)
{ {
Id = "pistol", Id = "pistol",
Name = "Пистолет", Name = "Пистолет",
Damage = GameConstants.PISTOL_BASE_DAMAGE,
IdleTexture = "texture/pistol/idle.png", IdleTexture = "texture/pistol/idle.png",
FireAnimationDuration = 0.25f, FireAnimationDuration = 0.25f,
FireAnimation = 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() ShootPattern = new LineShootPattern()
}; };
@@ -29,15 +33,18 @@ public class WeaponData
/// Data for the "Shotgun" weapon. /// Data for the "Shotgun" weapon.
/// </summary> /// </summary>
public static WeaponData Shotgun => public static WeaponData Shotgun =>
new(10) new(GameConstants.SHOTGUN_MAX_AMMO)
{ {
Id = "shotgun", Id = "shotgun",
Name = "Дробовик", Name = "Дробовик",
Damage = GameConstants.SHOTGUN_BASE_DAMAGE,
IdleTexture = "texture/shotgun/idle.png", IdleTexture = "texture/shotgun/idle.png",
FireAnimationDuration = 0.1f, FireAnimationDuration = 0.1f,
FireAnimation = { "texture/shotgun/fire1.png", "texture/shotgun/fire2.png" }, FireAnimation = { "texture/shotgun/fire1.png", "texture/shotgun/fire2.png" },
Damage = 5, ShootPattern =
ShootPattern = new RandomFlatSpreadShootPattern(MathHelper.DegreesToRadians(10), 40) new RandomFlatSpreadShootPattern(
MathHelper.DegreesToRadians(GameConstants.SHOTGUN_SHOOT_PATTERN_ANGLE_DEGREES),
GameConstants.SHOTGUN_SHOOT_PATTERN_COUNT)
}; };
/// <summary> /// <summary>

View File

@@ -46,10 +46,6 @@ public class ObjectSpawner : IUpdate
_condition.OnTrue += Spawn; _condition.OnTrue += Spawn;
} }
/// <summary>
/// Updates the state of the spawner, evaluating the condition to determine if a new object should spawn.
/// </summary>
/// <param name="parDeltaTime">The time elapsed since the last update, in seconds.</param>
public void Update(double parDeltaTime) public void Update(double parDeltaTime)
{ {
_condition.Update(parDeltaTime); _condition.Update(parDeltaTime);