Een strategisch fundament met grid-gebaseerde plaatsing en dynamische preview mechanics.
Het hart van dit project is de TowerPlacementManager. Dit systeem stelt spelers in staat om torens intuïtief te plaatsen met een real-time preview die visuele feedback geeft over de geldigheid van de locatie.
De preview verandert van kleur op basis van of een locatie geblokkeerd is of niet, wat zorgt voor een naadloze gebruikerservaring.
void HandlePlacementPreview()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 1000f, groundLayer))
{
Vector3 placementPos = hit.point;
// Snap to grid if needed
placementPos = SnapToGrid(placementPos);
towerPreview.transform.position = placementPos;
// Check if placement is valid
bool isValid = IsValidPlacement(placementPos);
UpdatePreviewColor(isValid);
}
}
Om precisie te garanderen, maakt het systeem gebruik van een snapping-algoritme. Dit zorgt ervoor dat alle torens perfect uitgelijnd zijn op een grid van 1x1 eenheden, wat cruciaal is voor de tactische layout van het level.
Vector3 SnapToGrid(Vector3 position)
{
float gridSize = 1f;
float x = Mathf.Round(position.x / gridSize) * gridSize;
float z = Mathf.Round(position.z / gridSize) * gridSize;
return new Vector3(x, position.y, z);
}
Validatie gebeurt via Physics.OverlapSphere, waardoor we direct kunnen zien of een nieuwe toren een bestaand object zou overlappen. Dit voorkomt dat spelers meerdere torens op dezelfde plek bouwen.
bool IsValidPlacement(Vector3 position)
{
// Check if position is blocked by other towers
Collider[] colliders = Physics.OverlapSphere(position, 0.5f);
foreach (var col in colliders)
{
if (col.CompareTag("Tower"))
return false;
}
return true;
}
using UnityEngine;
public class TowerPlacementManager : MonoBehaviour
{
[SerializeField] private LayerMask groundLayer;
[SerializeField] private GameObject towerPrefab;
[SerializeField] private int towerCost = 100;
[SerializeField] private Material previewMaterial;
[SerializeField] private Color validColor = new Color(0, 1, 0, 0.5f);
[SerializeField] private Color invalidColor = new Color(1, 0, 0, 0.5f);
private GameObject towerPreview;
private bool isPlacementMode = false;
private Renderer[] previewRenderers;
void Update()
{
if (isPlacementMode)
{
HandlePlacementPreview();
if (Input.GetMouseButtonDown(0))
{
TryPlaceTower();
}
if (Input.GetMouseButtonDown(1) || Input.GetKeyDown(KeyCode.Escape))
{
ExitPlacementMode();
}
}
}
public void EnterPlacementMode(GameObject prefab, int cost)
{
if (!GameManager.Instance.CanAfford(cost)) return;
isPlacementMode = true;
towerPrefab = prefab;
towerCost = cost;
towerPreview = Instantiate(prefab);
SetPreviewMaterial(towerPreview);
UpdatePreviewPosition();
}
private void UpdatePreviewPosition()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 1000f, groundLayer))
{
Vector3 pos = SnapToGrid(hit.point);
towerPreview.transform.position = pos;
UpdatePreviewColor(IsValidPlacement(pos));
}
}
// ... (rest van de methodes zoals hierboven beschreven)
}