mirror of
https://github.com/ryzij/Cube-Tower-Defense.git
synced 2026-07-14 01:56:57 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class AudioManager : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private AudioSource[] _grassBlockDestroySound;
|
||||
private int _grassSoundIndex = 0;
|
||||
|
||||
public void PlayBlockDestroySound(BlockScript block)
|
||||
{
|
||||
switch (block.Type)
|
||||
{
|
||||
case BlockScript.BlockType.Grass:
|
||||
case BlockScript.BlockType.PathFinish:
|
||||
if (_grassBlockDestroySound == null)
|
||||
return;
|
||||
|
||||
_grassBlockDestroySound[_grassSoundIndex].Play();
|
||||
_grassSoundIndex = (_grassSoundIndex + 1) % _grassBlockDestroySound.Length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44efdad54537f514eb583c74783d7f0e
|
||||
@@ -0,0 +1,63 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class BlockDetector : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private InputAction _clickAction;
|
||||
[SerializeField] private UnityEvent<BlockScript> _onBlockClicked;
|
||||
[SerializeField] private UnityEvent<BlockScript> _onBlockDetected;
|
||||
|
||||
public event UnityAction<BlockScript> OnBlockClicked
|
||||
{
|
||||
add => _onBlockClicked.AddListener(value);
|
||||
remove => _onBlockClicked.RemoveListener(value);
|
||||
}
|
||||
|
||||
public event UnityAction<BlockScript> OnBlockDetected
|
||||
{
|
||||
add => _onBlockDetected.AddListener(value);
|
||||
remove => _onBlockDetected.RemoveListener(value);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_clickAction.Enable();
|
||||
_clickAction.performed += Click_performed;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_clickAction.performed -= Click_performed;
|
||||
_clickAction.Disable();
|
||||
}
|
||||
|
||||
private void Click_performed(InputAction.CallbackContext context)
|
||||
{
|
||||
var clickPosition = Vector2.zero;
|
||||
if (Touchscreen.current != null)
|
||||
clickPosition = Touchscreen.current.position.ReadValue();
|
||||
if (clickPosition == Vector2.zero)
|
||||
clickPosition = Mouse.current.position.ReadValue();
|
||||
|
||||
var block = DetectBlockOnPosition(clickPosition);
|
||||
if (block != null)
|
||||
_onBlockClicked?.Invoke(block);
|
||||
}
|
||||
|
||||
private BlockScript DetectBlockOnPosition(Vector2 position)
|
||||
{
|
||||
var ray = Camera.main.ScreenPointToRay(position);
|
||||
if (Physics.Raycast(ray, out var hit) && hit.transform.CompareTag("GrassBlock"))
|
||||
return hit.transform.GetComponent<BlockScript>();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
var block = DetectBlockOnPosition(Mouse.current.position.ReadValue());
|
||||
if (block != null)
|
||||
_onBlockDetected?.Invoke(block);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd2070fb0c6397f10b0302d1f156f6e6
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class BlockScript : MonoBehaviour
|
||||
{
|
||||
public enum BlockType
|
||||
{
|
||||
None,
|
||||
Grass,
|
||||
Sand,
|
||||
PathFinish
|
||||
}
|
||||
|
||||
[SerializeField] private BlockType _type = BlockType.None;
|
||||
public BlockType Type { get => _type; protected set => _type = value; }
|
||||
|
||||
public bool IsPath => _type is BlockType.Sand or BlockType.PathFinish;
|
||||
|
||||
public List<BlockScript> GetNeighbors()
|
||||
{
|
||||
var neighbors = new List<BlockScript>();
|
||||
var ray = new Ray(transform.position, Vector3.up);
|
||||
|
||||
if (CheckNeighbor(ray, out var neighbor))
|
||||
neighbors.Add(neighbor);
|
||||
ray.direction = Vector3.forward;
|
||||
if (CheckNeighbor(ray, out neighbor))
|
||||
neighbors.Add(neighbor);
|
||||
ray.direction = Vector3.right;
|
||||
if (CheckNeighbor(ray, out neighbor))
|
||||
neighbors.Add(neighbor);
|
||||
ray.direction = Vector3.down;
|
||||
if (CheckNeighbor(ray, out neighbor))
|
||||
neighbors.Add(neighbor);
|
||||
ray.direction = Vector3.back;
|
||||
if (CheckNeighbor(ray, out neighbor))
|
||||
neighbors.Add(neighbor);
|
||||
ray.direction = Vector3.left;
|
||||
if (CheckNeighbor(ray, out neighbor))
|
||||
neighbors.Add(neighbor);
|
||||
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
private static bool CheckNeighbor(Ray ray, out BlockScript neighbor)
|
||||
{
|
||||
if (Physics.Raycast(ray, out var hit, 1f))
|
||||
return hit.transform.TryGetComponent(out neighbor);
|
||||
|
||||
neighbor = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d6715c95501a4f49bd34c8832850f32
|
||||
@@ -0,0 +1,36 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class BlockSelector : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private BlockDetector _blockDetector;
|
||||
[SerializeField] private Material _selectedMaterial;
|
||||
|
||||
private Renderer _selectedBlockRenderer;
|
||||
private Material _oldMaterial;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_blockDetector.OnBlockDetected += OnBlockDetected;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_blockDetector.OnBlockDetected -= OnBlockDetected;
|
||||
|
||||
if (_selectedBlockRenderer != null)
|
||||
{
|
||||
_selectedBlockRenderer.material = _oldMaterial;
|
||||
_selectedBlockRenderer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBlockDetected(BlockScript block)
|
||||
{
|
||||
if (_selectedBlockRenderer != null)
|
||||
_selectedBlockRenderer.material = _oldMaterial;
|
||||
|
||||
_selectedBlockRenderer = block.GetComponent<Renderer>();
|
||||
_oldMaterial = _selectedBlockRenderer.material;
|
||||
_selectedBlockRenderer.material = _selectedMaterial;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ae3ce76e48e194429448bf2071e7073
|
||||
@@ -0,0 +1,13 @@
|
||||
using UnityEngine;
|
||||
|
||||
public static class ComponentHelper
|
||||
{
|
||||
public static T GetComponentInChildrenWithoutParent<T>(this Component obj) where T : Component
|
||||
{
|
||||
foreach (var comp in obj.GetComponentsInChildren<T>())
|
||||
if (comp.gameObject != obj.gameObject)
|
||||
return comp;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9575f79ebc216754fb44b8066ae811b2
|
||||
@@ -0,0 +1,44 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class Debugger : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private GameManager _gameManager;
|
||||
[SerializeField] private SandPathBuildService _sandPathBuildService;
|
||||
[SerializeField] private TurretsShop _turretShop;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_gameManager.OnStateChanged += OnGameStateChanged;
|
||||
_sandPathBuildService.OnBuildComplete += OnBuildComplete;
|
||||
_turretShop.OnTurretSelected += OnTurretSelected;
|
||||
_turretShop.OnTurretDeselected += OnTurretDeselected;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_gameManager.OnStateChanged -= OnGameStateChanged;
|
||||
_sandPathBuildService.OnBuildComplete -= OnBuildComplete;
|
||||
_turretShop.OnTurretSelected -= OnTurretSelected;
|
||||
_turretShop.OnTurretDeselected -= OnTurretDeselected;
|
||||
}
|
||||
|
||||
private static void OnGameStateChanged(GameManager.GameState newState)
|
||||
{
|
||||
print("State changed, current state: " + newState);
|
||||
}
|
||||
|
||||
private static void OnBuildComplete()
|
||||
{
|
||||
print("Build complete");
|
||||
}
|
||||
|
||||
private static void OnTurretSelected(TurretShopItem item)
|
||||
{
|
||||
print("Turret selected: " + item.TurretPrefab.name);
|
||||
}
|
||||
|
||||
private static void OnTurretDeselected()
|
||||
{
|
||||
print("Turret deselected");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f920e63c4a34e61a183a87c8c35d534
|
||||
timeCreated: 1777495310
|
||||
@@ -0,0 +1,89 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class Enemy : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private SandPathBuildService _pathService;
|
||||
[SerializeField] private float _health = 5f;
|
||||
[SerializeField] private float _speed = 1f;
|
||||
[SerializeField] private float _damage = 1f;
|
||||
[SerializeField] private int _killReward = 10;
|
||||
[SerializeField] private UnityEvent<float> _onHealthChanged;
|
||||
[SerializeField] private UnityEvent<OnEnemyDeathEventArgs> _onDeath;
|
||||
|
||||
private Queue<Vector3> _path;
|
||||
private Vector3 _target;
|
||||
|
||||
public event UnityAction<float> OnHealthChanged
|
||||
{
|
||||
add => _onHealthChanged.AddListener(value);
|
||||
remove => _onHealthChanged.RemoveListener(value);
|
||||
}
|
||||
|
||||
public event UnityAction<OnEnemyDeathEventArgs> OnDeath
|
||||
{
|
||||
add => _onDeath.AddListener(value);
|
||||
remove => _onDeath.RemoveListener(value);
|
||||
}
|
||||
|
||||
public SandPathBuildService PathBuildService
|
||||
{
|
||||
get => _pathService;
|
||||
set => _pathService = value;
|
||||
}
|
||||
|
||||
public float Health
|
||||
{
|
||||
get => _health;
|
||||
private set
|
||||
{
|
||||
_health = value;
|
||||
_onHealthChanged?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
||||
public float Damage { get => _damage; set => _damage = value; }
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_path = new Queue<Vector3>(_pathService.GetPath());
|
||||
_target = _path.Dequeue();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (transform.position == _target)
|
||||
{
|
||||
if (_path.Count == 0) return;
|
||||
_target = _path.Dequeue();
|
||||
}
|
||||
|
||||
transform.position = Vector3.MoveTowards(transform.position, _target, _speed * Time.deltaTime);
|
||||
transform.LookAt(_target);
|
||||
}
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (!other.TryGetComponent(out TurretBullet bullet))
|
||||
return;
|
||||
|
||||
TakeDamage(bullet.Damage);
|
||||
Destroy(other.gameObject);
|
||||
}
|
||||
|
||||
public void TakeDamage(float damage)
|
||||
{
|
||||
Health -= damage;
|
||||
if (Health <= 0f)
|
||||
{
|
||||
_onDeath?.Invoke(new OnEnemyDeathEventArgs { KillReward = _killReward });
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public class OnEnemyDeathEventArgs
|
||||
{
|
||||
public int KillReward { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc6b4f7ed5ed4fdbbcfc85d14e3e9ad9
|
||||
timeCreated: 1774365562
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class EnemySpawner : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private GameManager _gameManager;
|
||||
[SerializeField] private SandPathBuildService _pathBuildService;
|
||||
[SerializeField] private Transform _enemyHolder;
|
||||
[SerializeField] private Transform _spawnPoint;
|
||||
[SerializeField] private Wallet _wallet;
|
||||
|
||||
//private readonly List<Enemy> _enemies = new();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (_gameManager == null)
|
||||
_gameManager = FindAnyObjectByType<GameManager>();
|
||||
if (_enemyHolder == null)
|
||||
_enemyHolder = transform;
|
||||
if (_spawnPoint == null)
|
||||
_spawnPoint = transform;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_gameManager.OnLevelChanged += OnLevelChanged;
|
||||
}
|
||||
private void OnDisable()
|
||||
{
|
||||
_gameManager.OnLevelChanged -= OnLevelChanged;
|
||||
}
|
||||
|
||||
private void OnLevelChanged(Level level) => StartCoroutine(SpawnCoroutine(level));
|
||||
|
||||
private IEnumerator SpawnCoroutine(Level level)
|
||||
{
|
||||
var wait = new WaitForSeconds(level.LevelTimeSec / level.EnemiesPrefabs.Count);
|
||||
|
||||
foreach (var prefab in level.EnemiesPrefabs)
|
||||
{
|
||||
var enemy = Instantiate(prefab, _spawnPoint.position, _spawnPoint.rotation, _enemyHolder);
|
||||
enemy.PathBuildService = _pathBuildService;
|
||||
enemy.OnDeath += e => _wallet.AddMoney(e.KillReward);
|
||||
//_enemies.Add(enemy);
|
||||
|
||||
yield return wait;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c18267efc955fbe3928becc91bf4ba3
|
||||
@@ -0,0 +1,66 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
public class GameManager : MonoBehaviour
|
||||
{
|
||||
public enum GameState
|
||||
{
|
||||
BuildingPath,
|
||||
BuildingTurrets,
|
||||
Level
|
||||
}
|
||||
|
||||
[SerializeField] private Level[] _levels;
|
||||
[SerializeField] private SandPathBuildService _pathBuildService;
|
||||
[SerializeField] private UnityEvent<GameState> _onStateChanged;
|
||||
[SerializeField] private UnityEvent<Level> _onLevelChanged;
|
||||
|
||||
public event UnityAction<GameState> OnStateChanged
|
||||
{
|
||||
add => _onStateChanged.AddListener(value);
|
||||
remove => _onStateChanged.RemoveListener(value);
|
||||
}
|
||||
|
||||
public event UnityAction<Level> OnLevelChanged
|
||||
{
|
||||
add => _onLevelChanged.AddListener(value);
|
||||
remove => _onLevelChanged.RemoveListener(value);
|
||||
}
|
||||
|
||||
private int _currentLvlIndex = -1;
|
||||
|
||||
private GameState _currentState = GameState.BuildingPath;
|
||||
|
||||
public GameState CurrentState
|
||||
{
|
||||
get => _currentState;
|
||||
set
|
||||
{
|
||||
_currentState = value;
|
||||
_onStateChanged?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
||||
//public Level CurrentLevel => _levels[_currentLvlIndex];
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_pathBuildService.OnBuildComplete += OnBuildComplete;
|
||||
}
|
||||
private void OnDisable()
|
||||
{
|
||||
_pathBuildService.OnBuildComplete -= OnBuildComplete;
|
||||
}
|
||||
|
||||
private void OnBuildComplete()
|
||||
{
|
||||
CurrentState = GameState.BuildingTurrets;
|
||||
}
|
||||
|
||||
public void NextLevel()
|
||||
{
|
||||
_currentLvlIndex = (_currentLvlIndex + 1) % _levels.Length;
|
||||
CurrentState = GameState.Level;
|
||||
_onLevelChanged?.Invoke(_levels[_currentLvlIndex]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aec3c0c64e4509b5db4d419ad4c5cc6b
|
||||
@@ -0,0 +1,100 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class SandPathBuildService : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private GameManager _gameManager;
|
||||
[SerializeField] private BlockDetector _blockDetector;
|
||||
[SerializeField] private BlockScript _blockPrefab;
|
||||
[SerializeField] private BlockScript _grassBlockPrefab;
|
||||
[SerializeField] private BlockScript _pathStart;
|
||||
[SerializeField] private BlockScript _pathEnd;
|
||||
[SerializeField] private BlockScript[] _pathFinish;
|
||||
[SerializeField] private BlockScript[] _predefinedBlocks;
|
||||
|
||||
[SerializeField] private UnityEvent<BlockScript> _onBlockDestroy;
|
||||
[SerializeField] private UnityEvent _onBuildComplete;
|
||||
|
||||
public event UnityAction<BlockScript> OnBlockDestroy
|
||||
{
|
||||
add => _onBlockDestroy.AddListener(value);
|
||||
remove => _onBlockDestroy.RemoveListener(value);
|
||||
}
|
||||
public event UnityAction OnBuildComplete
|
||||
{
|
||||
add => _onBuildComplete.AddListener(value);
|
||||
remove => _onBuildComplete.RemoveListener(value);
|
||||
}
|
||||
|
||||
private BlockScript _currentBlock;
|
||||
private readonly List<BlockScript> _blocksInPath = new();
|
||||
|
||||
private void Start() => InitBlocks();
|
||||
|
||||
private void InitBlocks()
|
||||
{
|
||||
_currentBlock = _pathStart;
|
||||
_blocksInPath.AddRange(_predefinedBlocks);
|
||||
}
|
||||
|
||||
public void DestroyBlock(BlockScript block)
|
||||
{
|
||||
_onBlockDestroy?.Invoke(block);
|
||||
Destroy(block.gameObject);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_blockDetector.OnBlockClicked += OnBlockDetected;
|
||||
}
|
||||
private void OnDisable()
|
||||
{
|
||||
_blockDetector.OnBlockClicked -= OnBlockDetected;
|
||||
}
|
||||
|
||||
public void ResetPath()
|
||||
{
|
||||
// TODO: исправить удаление блоков финала пути
|
||||
for (int i = _predefinedBlocks.Length; i < _blocksInPath.Count; i++)
|
||||
{
|
||||
var block = _blocksInPath[i];
|
||||
Instantiate(_grassBlockPrefab, block.transform.position, block.transform.localRotation, block.transform.parent);
|
||||
Destroy(block.gameObject);
|
||||
}
|
||||
|
||||
_blocksInPath.Clear();
|
||||
InitBlocks();
|
||||
}
|
||||
|
||||
private void OnBlockDetected(BlockScript block)
|
||||
{
|
||||
if (_gameManager.CurrentState != GameManager.GameState.BuildingPath)
|
||||
return;
|
||||
if (!_currentBlock.GetNeighbors().Contains(block) ||
|
||||
block.GetNeighbors().Count((o) => o.Type == BlockScript.BlockType.Sand) > 1)
|
||||
return;
|
||||
|
||||
var t = block.transform;
|
||||
_currentBlock = Instantiate(_blockPrefab, t.position, t.localRotation, t.parent);
|
||||
_blocksInPath.Add(_currentBlock);
|
||||
if (_pathFinish.Contains(block))
|
||||
{
|
||||
_currentBlock = _pathEnd;
|
||||
_blocksInPath.Add(_currentBlock);
|
||||
_onBuildComplete?.Invoke();
|
||||
}
|
||||
|
||||
DestroyBlock(block);
|
||||
}
|
||||
|
||||
public IEnumerable<Vector3> GetPath() =>
|
||||
_blocksInPath.Select(b =>
|
||||
{
|
||||
var pos = b.transform.position;
|
||||
pos.y += 1f;
|
||||
|
||||
return pos;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2234a2a63b27a534f9fc6fdcdb15afcb
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13aa96d6e4bf50589a66618b4eb22f78
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[CreateAssetMenu(fileName = "Level_No", menuName = "Scriptable Objects/Level")]
|
||||
public class Level : ScriptableObject
|
||||
{
|
||||
[SerializeField] private Enemy[] _enemiesPrefabs;
|
||||
[SerializeField] private float _levelTimeSec = 10f;
|
||||
|
||||
public IReadOnlyCollection<Enemy> EnemiesPrefabs => _enemiesPrefabs;
|
||||
public float LevelTimeSec => _levelTimeSec;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1e1b282bef2878e089a42b9c8507311
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(TowerHealth))]
|
||||
public class Tower : MonoBehaviour
|
||||
{
|
||||
private TowerHealth _towerHealth;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_towerHealth = GetComponent<TowerHealth>();
|
||||
}
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (other.TryGetComponent(out Enemy enemy))
|
||||
_towerHealth.TakeDamage(enemy.Damage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49451834470586d42a0a0039b348f818
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
public class TowerHealth : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float _maxHealth = 100f;
|
||||
[SerializeField] private float _currentHealth = 100f;
|
||||
|
||||
[SerializeField] private UnityEvent<OnHealthChangedEventArgs> _onHealthChanged;
|
||||
|
||||
public event UnityAction<OnHealthChangedEventArgs> OnHealthChanged
|
||||
{
|
||||
add => _onHealthChanged.AddListener(value);
|
||||
remove => _onHealthChanged.RemoveListener(value);
|
||||
}
|
||||
|
||||
public float MaxHealth
|
||||
{
|
||||
get => _maxHealth;
|
||||
private set
|
||||
{
|
||||
_maxHealth = value;
|
||||
_onHealthChanged?.Invoke(new(_currentHealth, _maxHealth));
|
||||
}
|
||||
}
|
||||
|
||||
public float CurrentHealth
|
||||
{
|
||||
get => _currentHealth;
|
||||
private set
|
||||
{
|
||||
_currentHealth = value;
|
||||
_onHealthChanged?.Invoke(new(_currentHealth, _maxHealth));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (!other.TryGetComponent(out Enemy enemy))
|
||||
return;
|
||||
|
||||
TakeDamage(enemy.Damage);
|
||||
Destroy(enemy.gameObject);
|
||||
}
|
||||
|
||||
public void TakeDamage(float damage)
|
||||
{
|
||||
CurrentHealth -= damage;
|
||||
|
||||
// TODO: доделать проигрыш
|
||||
if (CurrentHealth <= 0)
|
||||
Debug.Log("Game over");
|
||||
}
|
||||
|
||||
public class OnHealthChangedEventArgs : EventArgs
|
||||
{
|
||||
public readonly float CurrentHealth;
|
||||
public readonly float MaxHealth;
|
||||
|
||||
public OnHealthChangedEventArgs(float currentHealth, float maxHealth)
|
||||
{
|
||||
CurrentHealth = currentHealth;
|
||||
MaxHealth = maxHealth;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73f23bf5d451b9d99a2529ebac821e47
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
public class TowerHealthViewer : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TowerHealth _towerHealth;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_towerHealth.OnHealthChanged += OnHealthChanged;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_towerHealth.OnHealthChanged -= OnHealthChanged;
|
||||
}
|
||||
|
||||
private static void OnHealthChanged(TowerHealth.OnHealthChangedEventArgs e)
|
||||
{
|
||||
print("Health changed: " + e.CurrentHealth);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 623cfd758f42513808424b0fdb743846
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
public class Turret : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TurretBullet _bulletPrefab;
|
||||
[SerializeField] private float _reloadTime = 1f;
|
||||
[SerializeField] private float _damage;
|
||||
[SerializeField] private float _distance;
|
||||
|
||||
private float _reloadTimer;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_reloadTimer >= _reloadTime)
|
||||
{
|
||||
SpawnBullet(Vector3.forward);
|
||||
SpawnBullet(Vector3.back);
|
||||
SpawnBullet(Vector3.left);
|
||||
SpawnBullet(Vector3.right);
|
||||
|
||||
_reloadTimer = 0f;
|
||||
}
|
||||
|
||||
_reloadTimer += Time.deltaTime;
|
||||
}
|
||||
|
||||
private void SpawnBullet(Vector3 direction)
|
||||
{
|
||||
if (!DetectEnemy(direction))
|
||||
return;
|
||||
|
||||
var rot = transform.rotation;
|
||||
rot.SetLookRotation(direction);
|
||||
Instantiate(_bulletPrefab, transform.position, rot, transform);
|
||||
}
|
||||
|
||||
private bool DetectEnemy(Vector3 direction) =>
|
||||
Physics.Raycast(transform.position, direction, out var hit, _bulletPrefab.Distance + _distance) &&
|
||||
hit.transform.TryGetComponent(out Enemy _);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28342e4845776bf5982ef6ad03926c37
|
||||
@@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class TurretBullet : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float _damage = 1f;
|
||||
[SerializeField] private float _speed = 5f;
|
||||
[SerializeField] private float _distance = 3f;
|
||||
|
||||
private Vector3 _spawnPos;
|
||||
|
||||
public float Damage => _damage;
|
||||
public float Distance => _distance;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_spawnPos = transform.position;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
transform.Translate(Vector3.forward * (_speed * Time.deltaTime));
|
||||
if (Vector3.Distance(transform.position, _spawnPos) > _distance)
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45192ee5599f42de7864fdec0f93ce27
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
[Serializable]
|
||||
public struct TurretShopItem
|
||||
{
|
||||
[SerializeField] private Turret _turretPrefab;
|
||||
[SerializeField] private Sprite _icon;
|
||||
[SerializeField] private int _price;
|
||||
|
||||
public readonly Turret TurretPrefab => _turretPrefab;
|
||||
public readonly Sprite Icon => _icon;
|
||||
public readonly int Price => _price;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4599f6d87f88c5e4bb120a45c1dc6e59
|
||||
@@ -0,0 +1,85 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class TurretsShop : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Wallet _wallet;
|
||||
[SerializeField] private BlockDetector _blockDetector;
|
||||
[SerializeField] private Transform _turretsHolder;
|
||||
[SerializeField] private InputAction _deselectAction;
|
||||
[SerializeField] private TurretShopItem[] _turretShopItems;
|
||||
[SerializeField] private UnityEvent<TurretShopItem> _onTurretSelected;
|
||||
[SerializeField] private UnityEvent _onTurretDeselected;
|
||||
|
||||
public event UnityAction<TurretShopItem> OnTurretSelected
|
||||
{
|
||||
add => _onTurretSelected.AddListener(value);
|
||||
remove => _onTurretSelected.RemoveListener(value);
|
||||
}
|
||||
|
||||
public event UnityAction OnTurretDeselected
|
||||
{
|
||||
add => _onTurretDeselected.AddListener(value);
|
||||
remove => _onTurretDeselected.RemoveListener(value);
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<TurretShopItem> TurretShopItems => _turretShopItems;
|
||||
|
||||
private TurretShopItem _selectedTurret;
|
||||
private bool _isTurretSelected = false;
|
||||
|
||||
public void SelectTurret(TurretShopItem item)
|
||||
{
|
||||
_isTurretSelected = _wallet.Money >= item.Price;
|
||||
if (!_isTurretSelected)
|
||||
return;
|
||||
|
||||
_selectedTurret = item;
|
||||
_onTurretSelected?.Invoke(item);
|
||||
}
|
||||
|
||||
public void DeselectTurret()
|
||||
{
|
||||
_isTurretSelected = false;
|
||||
_onTurretDeselected?.Invoke();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_deselectAction.Enable();
|
||||
_deselectAction.performed += DeselectActionPerformed;
|
||||
|
||||
_blockDetector.OnBlockClicked += OnBlockClicked;
|
||||
}
|
||||
private void OnDisable()
|
||||
{
|
||||
_deselectAction.performed -= DeselectActionPerformed;
|
||||
_deselectAction.Disable();
|
||||
|
||||
_blockDetector.OnBlockClicked -= OnBlockClicked;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (_turretsHolder == null)
|
||||
_turretsHolder = transform;
|
||||
}
|
||||
|
||||
private void DeselectActionPerformed(InputAction.CallbackContext _) => DeselectTurret();
|
||||
|
||||
private void OnBlockClicked(BlockScript block)
|
||||
{
|
||||
if (!_isTurretSelected || _selectedTurret.Price > _wallet.Money)
|
||||
return;
|
||||
|
||||
var pos = block.transform.position;
|
||||
pos.y += 1;
|
||||
Instantiate(_selectedTurret.TurretPrefab, pos, Quaternion.identity, _turretsHolder);
|
||||
|
||||
_wallet.TakeMoney(_selectedTurret.Price);
|
||||
if (_wallet.Money < _selectedTurret.Price)
|
||||
DeselectTurret();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5980606f117d314418be8bbb5abf9a95
|
||||
@@ -0,0 +1,70 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class TurretsShopViewer : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TurretsShop _shop;
|
||||
[SerializeField] private Wallet _wallet;
|
||||
[SerializeField] private GameManager _gameManager;
|
||||
[SerializeField] private Button _buttonPrefab;
|
||||
|
||||
private Animator _animator;
|
||||
private bool _hidden = true;
|
||||
private readonly Dictionary<Button, TurretShopItem> _buttons = new();
|
||||
|
||||
private static readonly int _hideAnimation = Animator.StringToHash("HideTurretShopPanelAnimation");
|
||||
private static readonly int _showAnimation = Animator.StringToHash("ShowTurretShopPanelAnimation");
|
||||
|
||||
private void Start()
|
||||
{
|
||||
foreach (var item in _shop.TurretShopItems)
|
||||
{
|
||||
var button = Instantiate(_buttonPrefab, transform);
|
||||
var icon = button.GetComponentInChildrenWithoutParent<Image>();
|
||||
if (icon != null && item.Icon != null)
|
||||
{
|
||||
icon.gameObject.SetActive(true);
|
||||
icon.sprite = item.Icon;
|
||||
}
|
||||
|
||||
button.onClick.AddListener(() => _shop.SelectTurret(item));
|
||||
_buttons.Add(button, item);
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_gameManager.OnStateChanged += OnGameStateChanged;
|
||||
_wallet.OnMoneyChanged += OnMoneyChanged;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_gameManager.OnStateChanged -= OnGameStateChanged;
|
||||
_wallet.OnMoneyChanged -= OnMoneyChanged;
|
||||
}
|
||||
|
||||
private void OnGameStateChanged(GameManager.GameState state)
|
||||
{
|
||||
if (!_hidden || state != GameManager.GameState.BuildingTurrets)
|
||||
return;
|
||||
|
||||
_animator.Play(_showAnimation);
|
||||
_hidden = false;
|
||||
}
|
||||
|
||||
private void OnMoneyChanged(int money)
|
||||
{
|
||||
foreach (var (button, item) in _buttons)
|
||||
{
|
||||
button.interactable = money >= item.Price;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13f8d814a03532843895b328349ccfd5
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef3ea4b0304aec24d8f2b6ed14e432d1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class GameMenuButtons : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private GameManager _gameManager;
|
||||
[SerializeField] private SandPathBuildService _sandPathBuildService;
|
||||
[SerializeField] private Button _nextLevelButton;
|
||||
[SerializeField] private Button _resetPathButton;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_gameManager.OnStateChanged += OnStateChanged;
|
||||
|
||||
if (_resetPathButton != null)
|
||||
_resetPathButton.onClick.AddListener(OnResetButtonClick);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_gameManager.OnStateChanged -= OnStateChanged;
|
||||
|
||||
if (_resetPathButton != null)
|
||||
_resetPathButton.onClick.RemoveListener(OnResetButtonClick);
|
||||
}
|
||||
|
||||
private void OnStateChanged(GameManager.GameState newState)
|
||||
{
|
||||
_nextLevelButton.interactable = newState != GameManager.GameState.BuildingPath;
|
||||
if (!_nextLevelButton.interactable || _resetPathButton == null)
|
||||
return;
|
||||
|
||||
_resetPathButton.onClick.RemoveAllListeners();
|
||||
Destroy(_resetPathButton.gameObject);
|
||||
_resetPathButton = null;
|
||||
}
|
||||
|
||||
private void OnResetButtonClick()
|
||||
{
|
||||
_sandPathBuildService.ResetPath();
|
||||
_gameManager.CurrentState = GameManager.GameState.BuildingPath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b08066ad0060a5d4fb8e8d7d9dadc514
|
||||
@@ -0,0 +1,35 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
public class Wallet : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private int _money;
|
||||
[SerializeField] private UnityEvent<int> _onMoneyChanged;
|
||||
|
||||
public event UnityAction<int> OnMoneyChanged
|
||||
{
|
||||
add => _onMoneyChanged.AddListener(value);
|
||||
remove => _onMoneyChanged.RemoveListener(value);
|
||||
}
|
||||
|
||||
public int Money
|
||||
{
|
||||
get => _money;
|
||||
private set
|
||||
{
|
||||
_money = value;
|
||||
_onMoneyChanged?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddMoney(int money) => Money += money;
|
||||
|
||||
public bool TakeMoney(int money)
|
||||
{
|
||||
if (Money < money)
|
||||
return false;
|
||||
|
||||
Money -= money;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5c1bdc2782c2a7b2a0a156402dbc325
|
||||
Reference in New Issue
Block a user