276 lines
9.2 KiB
C#
276 lines
9.2 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
[RequireComponent(typeof(Camera))]
|
|
public class CameraController : MonoBehaviour
|
|
{
|
|
public float scrollSpeed;
|
|
public RectTransform unitSelector;
|
|
// TODO: this is not ideal.
|
|
public List<Minerals> minerals;
|
|
|
|
private Camera _camera;
|
|
private Keyboard _keyboard;
|
|
private Mouse _mouse;
|
|
private Transform _transform;
|
|
private Vector3 _positionChange;
|
|
private bool _isSelecting;
|
|
private Rect _selectorRect;
|
|
private readonly List<Unit> _selectedUnits = new List<Unit>();
|
|
private Building _currentBuilding;
|
|
private bool _wantsBuildBarracks;
|
|
|
|
private void Start()
|
|
{
|
|
_mouse = Mouse.current;
|
|
_keyboard = Keyboard.current;
|
|
_transform = transform;
|
|
_positionChange = Vector3.zero;
|
|
_camera = GetComponent<Camera>();
|
|
|
|
Cursor.lockState = CursorLockMode.Confined;
|
|
var pivot = unitSelector.pivot;
|
|
pivot.x = 0;
|
|
pivot.y = 0;
|
|
unitSelector.pivot = pivot;
|
|
|
|
Team.Minerals = 10;
|
|
|
|
_keyboard.onTextInput += OnTextInput;
|
|
}
|
|
|
|
private void OnTextInput(char ch)
|
|
{
|
|
var keyControl = _keyboard.FindKeyOnCurrentKeyboardLayout(ch.ToString());
|
|
|
|
if (_currentBuilding != null && keyControl != null)
|
|
{
|
|
_currentBuilding.ProcessKeyInput(keyControl.keyCode);
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (_keyboard.escapeKey.wasPressedThisFrame)
|
|
{
|
|
Cursor.lockState = CursorLockMode.None;
|
|
}
|
|
#endif
|
|
|
|
if (!Application.isFocused)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var mousePos = _mouse.position.ReadValue();
|
|
|
|
_positionChange.x = 0;
|
|
_positionChange.y = 0;
|
|
if (mousePos.x <= 1)
|
|
{
|
|
_positionChange.x -= scrollSpeed * Time.deltaTime;
|
|
}
|
|
|
|
if (mousePos.x >= Screen.width - 1)
|
|
{
|
|
_positionChange.x += scrollSpeed * Time.deltaTime;
|
|
}
|
|
|
|
if (mousePos.y <= 1)
|
|
{
|
|
_positionChange.y -= scrollSpeed * Time.deltaTime;
|
|
}
|
|
|
|
if (mousePos.y >= Screen.height - 1)
|
|
{
|
|
_positionChange.y += scrollSpeed * Time.deltaTime;
|
|
}
|
|
|
|
_transform.position += _positionChange;
|
|
|
|
if (_mouse.rightButton.wasPressedThisFrame)
|
|
{
|
|
// TODO: pick logic, if the mouse was not dragged then it should select whatever is in the tile.
|
|
var worldPos = _camera.ScreenToWorldPoint(mousePos);
|
|
worldPos.x = Mathf.RoundToInt(worldPos.x);
|
|
worldPos.y = Mathf.RoundToInt(worldPos.y);
|
|
worldPos.z = 0;
|
|
|
|
var hasIssuedCommand = false;
|
|
foreach (var building in Team.AllBuildings)
|
|
{
|
|
if (building.buildingCollider.OverlapPoint(worldPos) && building.isUnderConstruction)
|
|
{
|
|
//var worker = Team.AllUnits.FirstOrDefault() as Worker;
|
|
var worker = _selectedUnits.FirstOrDefault(u => u is Worker) as Worker;
|
|
if (worker)
|
|
{
|
|
hasIssuedCommand = true;
|
|
worker.ConstructBuilding(building, worldPos);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
foreach (var mineral in minerals)
|
|
{
|
|
if (mineral.boxCollider.OverlapPoint(worldPos))
|
|
{
|
|
var cmd = Team.AllBuildings.FirstOrDefault(b => b.name == "CommandCenter");
|
|
// Not the best, but it will do.
|
|
// TODO: basically will need to search all buildings for command centers (should be a type?) then find the closest to the patch.
|
|
if (cmd)
|
|
{
|
|
var workers = _selectedUnits.FindAll(u => u is Worker);
|
|
hasIssuedCommand = workers.Count > 0;
|
|
Debug.Log($"has issued cmd: {hasIssuedCommand}");
|
|
workers.ForEach(w => ((Worker)w).StartMining(mineral,
|
|
mineral.transform.position,
|
|
cmd.transform.position));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasIssuedCommand)
|
|
{
|
|
MoveAllSelectedUnits(worldPos);
|
|
}
|
|
}
|
|
|
|
// TODO: for the selection box, we should select whatever thing there is most of in the box.
|
|
// IE: if there is one worker but 3 combat units, then select the 3 combat units.
|
|
// This is not ideal but since the prototype for iteration 0 is limited to 2 buildings, a worker, and a combat
|
|
// unit for the types of selectables, I think it will be acceptable until I add more stuff.
|
|
if (_mouse.leftButton.wasPressedThisFrame && !_wantsBuildBarracks)
|
|
{
|
|
_isSelecting = true;
|
|
_selectorRect = unitSelector.rect;
|
|
_selectorRect.min = _mouse.position.ReadValue();
|
|
}
|
|
|
|
if (_isSelecting)
|
|
{
|
|
_selectorRect.max = _mouse.position.ReadValue();
|
|
if (_mouse.leftButton.wasReleasedThisFrame)
|
|
{
|
|
// Needs to be called before we clear the selector rect.
|
|
FillSelection();
|
|
_isSelecting = false;
|
|
_selectorRect.min = Vector2.zero;
|
|
_selectorRect.max = Vector2.zero;
|
|
unitSelector.anchoredPosition = _selectorRect.min;
|
|
unitSelector.sizeDelta = _selectorRect.max;
|
|
}
|
|
|
|
Vector2 min;
|
|
min.x = _selectorRect.min.x > _selectorRect.max.x ? _selectorRect.max.x : _selectorRect.min.x;
|
|
min.y = _selectorRect.min.y > _selectorRect.max.y ? _selectorRect.max.y : _selectorRect.min.y;
|
|
|
|
Vector2 max;
|
|
max.x = _selectorRect.min.x > _selectorRect.max.x ? _selectorRect.min.x : _selectorRect.max.x;
|
|
max.y = _selectorRect.min.y > _selectorRect.max.y ? _selectorRect.min.y : _selectorRect.max.y;
|
|
|
|
unitSelector.anchoredPosition = min;
|
|
unitSelector.sizeDelta = max - min;
|
|
}
|
|
|
|
// if (_keyboard.sKey.wasPressedThisFrame && _currentBuilding)
|
|
// {
|
|
// _currentBuilding.BuildWorker();
|
|
// }
|
|
|
|
// TODO: this needs to cost money
|
|
// B->B build barracks
|
|
if (_selectedUnits.Count > 0)
|
|
{
|
|
if (_keyboard.bKey.wasPressedThisFrame)
|
|
{
|
|
_wantsBuildBarracks = true;
|
|
}
|
|
}
|
|
|
|
if (_wantsBuildBarracks && _selectedUnits.Count > 0)
|
|
{
|
|
if (_mouse.leftButton.wasPressedThisFrame)
|
|
{
|
|
var worldPos = _camera.ScreenToWorldPoint(mousePos);
|
|
worldPos.z = 0;
|
|
worldPos.x = Mathf.RoundToInt(worldPos.x);
|
|
worldPos.y = Mathf.RoundToInt(worldPos.y);
|
|
|
|
var worker = _selectedUnits.FirstOrDefault() as Worker;
|
|
if (worker)
|
|
{
|
|
worker.BuildBarracks(worldPos);
|
|
_wantsBuildBarracks = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_wantsBuildBarracks = false;
|
|
}
|
|
// Barracks -> A marine
|
|
// B->C command center.
|
|
}
|
|
|
|
private void FillSelection()
|
|
{
|
|
_selectedUnits.Clear();
|
|
|
|
var worldMin = _camera.ScreenToWorldPoint(_selectorRect.min);
|
|
var worldMax = _camera.ScreenToWorldPoint(_selectorRect.max);
|
|
|
|
var min = Vector3.zero;
|
|
min.x = worldMin.x > worldMax.x ? worldMax.x : worldMin.x;
|
|
min.y = worldMin.y > worldMax.y ? worldMax.y : worldMin.y;
|
|
|
|
var max = Vector3.zero;
|
|
max.x = worldMin.x > worldMax.x ? worldMin.x : worldMax.x;
|
|
max.y = worldMin.y > worldMax.y ? worldMin.y : worldMax.y;
|
|
|
|
var hasUnits = false;
|
|
foreach (var unit in Team.AllUnits)
|
|
{
|
|
var pos = unit.transform.position;
|
|
if (pos.x > min.x && pos.y > min.y &&
|
|
pos.x < max.x && pos.y < max.y)
|
|
{
|
|
_selectedUnits.Add(unit);
|
|
hasUnits = true;
|
|
}
|
|
}
|
|
|
|
// TODO: this is really not good, Ideally would just have a selectable type that provides abilities to the user.
|
|
// IE a unit selectable type provides the ability to move. A building selectable type provides the ability to manufacture a unit. etc.
|
|
if (!hasUnits)
|
|
{
|
|
// Try to select a building
|
|
foreach (var building in Team.AllBuildings)
|
|
{
|
|
if (building.buildingCollider.OverlapPoint(min)
|
|
|| building.buildingCollider.OverlapPoint(max))
|
|
{
|
|
Debug.Log("Building selected");
|
|
_currentBuilding = building;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void MoveAllSelectedUnits(Vector3 worldPos)
|
|
{
|
|
// TODO: not sure if pathfinding should happen here or on each unit.
|
|
// Probably start with each unit and when swarming logic is needed re-think the solution.
|
|
foreach (var unit in _selectedUnits)
|
|
{
|
|
unit.MoveTo(worldPos);
|
|
}
|
|
}
|
|
}
|