using System.Collections; using System.Collections...
Creado el: 26 de mayo de 2025
Creado el: 26 de mayo de 2025
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class BuildingGridPlacer : BuildingPlacer
{
public static bool IsPlacingBuilding = false;
textpublic globalControl scriptGlobalUI; public ap0Control script0UI; public Vector2 cellSize = new Vector2(1, 1); public Vector2 gridOffset; public Renderer gridRenderer; public bool isIsometric = false; private bool isMobile; private bool isDragging = false; private Vector2 lastTouchPosition;
#if UNITY_EDITOR
private void OnValidate()
{
_UpdateGridVisual();
}
#endif
textprivate void Start() { isMobile = Application.isMobilePlatform; _UpdateGridVisual(); _EnableGridVisual(false); } private void Update() { if (_buildingPrefab != null) { if (isMobile) { _HandleMobileInput(); } else { _HandlePCInput(); } } } private void _HandlePCInput() { if (_buildingPrefab != null) { if (Input.GetMouseButtonDown(1)) { _CancelBuildingMode(); return; } if (EventSystem.current.IsPointerOverGameObject()) { if (Input.GetMouseButtonDown(0)) { _CancelBuildingMode(); return; } if (_toBuild.activeSelf) _toBuild.SetActive(false); return; } else if (!_toBuild.activeSelf) _toBuild.SetActive(true); if (Input.GetKeyDown(KeyCode.Space)) { // esta madre no hace nada } Vector3 mouseWorldPos3D = Camera.main.ScreenToWorldPoint(Input.mousePosition); Vector2 mouseWorldPos = new Vector2(mouseWorldPos3D.x, mouseWorldPos3D.y); Vector2 snappedPos = isIsometric ? _ClampToNearestIsometric(mouseWorldPos, cellSize) : _ClampToNearest(mouseWorldPos, cellSize); _toBuild.transform.position = new Vector3(snappedPos.x, snappedPos.y, _toBuild.transform.position.z); foreach (SpriteRenderer sr in _toBuild.GetComponent<BuildingManager>().spriteRenderers) { sr.sortingOrder = _CalculateSortingOrder(sr.transform.position) + 1000; } if (Input.GetMouseButtonDown(0)) { BuildingManager m = _toBuild.GetComponent<BuildingManager>(); if (m.hasValidPlacement) { m.SetPlacementMode(PlacementMode.Fixed); foreach (SpriteRenderer sr in m.spriteRenderers) { sr.sortingOrder = _CalculateSortingOrder(sr.transform.position); } _buildingPrefab = null; _toBuild = null; _EnableGridVisual(false); script0UI.OcultarIndicaciones(); IsPlacingBuilding = false; } } } } private void _HandleMobileInput() { if (Input.touchCount > 0) { Touch touch = Input.GetTouch(0); // Siempre mostrar el preview mientras esté en modo construcción if (!_toBuild.activeSelf) _toBuild.SetActive(true); Vector3 touchWorldPos3D = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, Camera.main.nearClipPlane)); Vector2 touchWorldPos = new Vector2(touchWorldPos3D.x, touchWorldPos3D.y); switch (touch.phase) { case TouchPhase.Began: isDragging = true; lastTouchPosition = touchWorldPos; Vector2 snappedStartPos = isIsometric ? _ClampToNearestIsometric(touchWorldPos, cellSize) : _ClampToNearest(touchWorldPos, cellSize); _toBuild.transform.position = new Vector3(snappedStartPos.x, snappedStartPos.y, _toBuild.transform.position.z); break; case TouchPhase.Moved: if (isDragging) { Vector2 snappedPos = isIsometric ? _ClampToNearestIsometric(touchWorldPos, cellSize) : _ClampToNearest(touchWorldPos, cellSize); _toBuild.transform.position = new Vector3(snappedPos.x, snappedPos.y, _toBuild.transform.position.z); } break; case TouchPhase.Ended: case TouchPhase.Canceled: isDragging = false; break; } } } private void _CancelBuildingMode() { if (_toBuild != null) Destroy(_toBuild); _toBuild = null; _buildingPrefab = null; _EnableGridVisual(false); script0UI.OcultarIndicaciones(); IsPlacingBuilding = false; } protected override void _PrepareBuilding() { base._PrepareBuilding(); _EnableGridVisual(true); scriptGlobalUI.CloseGlobalPanels(); script0UI.MostrarIndicaciones(); IsPlacingBuilding = true; } private Vector2 _ClampToNearest(Vector2 pos, Vector2 cell) { Vector2 snapped = new Vector2( Mathf.Floor(pos.x / cell.x) * cell.x + (cell.x * 0.5f) + gridOffset.x, Mathf.Floor(pos.y / cell.y) * cell.y + (cell.y * 0.5f) + gridOffset.y ); return snapped; } private Vector2 _ClampToNearestIsometric(Vector2 pos, Vector2 cell) { // Medidas de medio tile float halfW = cell.x * 0.5f; float halfH = cell.y * 0.5f; // Convertir posición mundo a "coordenadas de rejilla" float isoX = (pos.x / halfW + pos.y / halfH) * 0.5f; float isoY = (pos.y / halfH - pos.x / halfW) * 0.5f; // Snap a entero int gridX = Mathf.RoundToInt(isoX); int gridY = Mathf.RoundToInt(isoY); // Volver a convertir a coordenadas mundo float worldX = (gridX - gridY) * halfW; float worldY = (gridX + gridY) * halfH; return new Vector2(worldX + gridOffset.x, worldY + gridOffset.y); } private void _EnableGridVisual(bool on) { if (gridRenderer == null) return; gridRenderer.gameObject.SetActive(on); } private void _UpdateGridVisual() { if (gridRenderer == null) return; gridRenderer.sharedMaterial.SetVector("_Cell_Size", new Vector4(cellSize.x, cellSize.y, 0, 0)); } private int _CalculateSortingOrder(Vector3 position) { return Mathf.RoundToInt(-position.y * 100); }
}
ayudame a hacer que si el usuario de android interactua con un elemento de la UI, el modo construccion se cancele, en _HandleMobileInput(). Hazlo de forma similar a como se hace en _HandlePCInput();
Aquí tienes una versión de _HandleMobileInput() que replica la misma lógica de cancelación usada en _HandlePCInput().
Lo esencial es aprovechar EventSystem.current.IsPointerOverGameObject(fingerId)
para saber si el toque comenzó sobre un elemento UI y, si es así, abortar el modo construcción con _CancelBuildingMode()
:
csharpprivate void _HandleMobileInput() { if (Input.touchCount == 0) return; Touch touch = Input.GetTouch(0); // ¿El dedo arrancó sobre un elemento de UI? bool overUI = EventSystem.current.IsPointerOverGameObject(touch.fingerId); // Si tocó UI –igual que en PC cuando se hace clic izquierdo sobre la UI–, // cancela el modo construcción y sal temprano. if (overUI) { if (touch.phase == TouchPhase.Began) { _CancelBuildingMode(); } if (_toBuild != null && _toBuild.activeSelf) _toBuild.SetActive(false); return; // No seguimos procesando el toque. } else if (_toBuild != null && !_toBuild.activeSelf) { // Si no estamos sobre UI, aseguramos que el preview esté visible. _toBuild.SetActive(true); } // ---------- Lógica normal de colocación ---------- Vector3 touchWorldPos3D = Camera.main.ScreenToWorldPoint( new Vector3(touch.position.x, touch.position.y, Camera.main.nearClipPlane)); Vector2 touchWorldPos = new Vector2(touchWorldPos3D.x, touchWorldPos3D.y); switch (touch.phase) { case TouchPhase.Began: isDragging = true; lastTouchPosition = touchWorldPos; Vector2 snappedStartPos = isIsometric ? _ClampToNearestIsometric(touchWorldPos, cellSize) : _ClampToNearest(touchWorldPos, cellSize); _toBuild.transform.position = new Vector3( snappedStartPos.x, snappedStartPos.y, _toBuild.transform.position.z); break; case TouchPhase.Moved: if (isDragging) { Vector2 snappedPos = isIsometric ? _ClampToNearestIsometric(touchWorldPos, cellSize) : _ClampToNearest(touchWorldPos, cellSize); _toBuild.transform.position = new Vector3( snappedPos.x, snappedPos.y, _toBuild.transform.position.z); } break; case TouchPhase.Ended: case TouchPhase.Canceled: isDragging = false; // Solo fija el edificio cuando el usuario suelta y la posición es válida BuildingManager m = _toBuild.GetComponent<BuildingManager>(); if (m.hasValidPlacement) { m.SetPlacementMode(PlacementMode.Fixed); foreach (SpriteRenderer sr in m.spriteRenderers) { sr.sortingOrder = _CalculateSortingOrder(sr.transform.position); } _buildingPrefab = null; _toBuild = null; _EnableGridVisual(false); script0UI.OcultarIndicaciones(); IsPlacingBuilding = false; } break; } }
Detección de UI en móvil
csharpbool overUI = EventSystem.current.IsPointerOverGameObject(touch.fingerId);
Esto funciona para cada dedo individual; si el primer toque arranca sobre la UI, lo detectamos.
Cancelación temprana
Al igual que en PC, si el primer frame (TouchPhase.Began
) ocurre sobre la UI se llama a _CancelBuildingMode()
y se sale de la función con return
.
Gestión del preview
_toBuild.SetActive(false)
), igual que en PC.Fijado del edificio
Aproveché el final del toque para fijar la estructura solamente si la colocación es válida; así mantienes el comportamiento coherente con PC.
Integra el método y, si lo deseas, elimina el antiguo. Con esto el usuario Android podrá cancelar la colocación simplemente tocando cualquier elemento de la interfaz.