Initial commit: Unity WordConnect project
This commit is contained in:
351
Assets/WordConnectGameToolkit/Scripts/Gameplay/Tile.cs
Normal file
351
Assets/WordConnectGameToolkit/Scripts/Gameplay/Tile.cs
Normal file
@ -0,0 +1,351 @@
|
||||
// // ©2015 - 2025 Candy Smith
|
||||
// // All rights reserved
|
||||
// // Redistribution of this software is strictly not allowed.
|
||||
// // Copy of this software can be obtained from unity asset store only.
|
||||
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// // THE SOFTWARE.
|
||||
|
||||
using DG.Tweening;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using WordsToolkit.Scripts.Settings;
|
||||
using WordsToolkit.Scripts.Gameplay.Managers;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.InputSystem;
|
||||
using WordsToolkit.Scripts.Enums;
|
||||
using WordsToolkit.Scripts.System;
|
||||
using VContainer;
|
||||
using VContainer.Unity;
|
||||
using WordsToolkit.Scripts.Audio;
|
||||
using WordsToolkit.Scripts.System.Haptic;
|
||||
|
||||
namespace WordsToolkit.Scripts.Gameplay
|
||||
{
|
||||
public class Tile : FillAndPreview, IPointerClickHandler
|
||||
{
|
||||
public TextMeshProUGUI character;
|
||||
public Image[] images;
|
||||
|
||||
[Header("Tile Colors")]
|
||||
public Color[] closedColors;
|
||||
private Color[] openColors = new Color[3];
|
||||
|
||||
private bool isSelected = false;
|
||||
private int wordNumber = -1;
|
||||
private bool isOpen = false;
|
||||
|
||||
[Header("Special Item")]
|
||||
[SerializeField] private GameObject specialItemPrefab; // Direct reference to the special item prefab
|
||||
|
||||
[Header("Hammer Animation")]
|
||||
[SerializeField] private GameObject hammerAnimationPrefab; // Reference to hammer animation prefab
|
||||
|
||||
// Added fields for special item support
|
||||
private bool hasSpecialItem = false;
|
||||
private Vector2Int specialItemPosition;
|
||||
private GameObject specialItemInstance; // Reference to the instantiated special item
|
||||
|
||||
// Simple selection state
|
||||
|
||||
private LevelManager levelManager;
|
||||
private FieldManager fieldManager;
|
||||
[SerializeField]
|
||||
private GameObject fx;
|
||||
|
||||
private IAudioService audioService;
|
||||
private IObjectResolver objectResolver;
|
||||
|
||||
[Inject]
|
||||
public void Construct(LevelManager levelManager, FieldManager fieldManager, IAudioService audioService, IObjectResolver objectResolver)
|
||||
{
|
||||
this.levelManager = levelManager;
|
||||
this.fieldManager = fieldManager;
|
||||
this.audioService = audioService;
|
||||
this.objectResolver = objectResolver;
|
||||
}
|
||||
|
||||
public void SetColors(ColorsTile colorsTile)
|
||||
{
|
||||
if (colorsTile == null)
|
||||
return;
|
||||
|
||||
openColors[0] = colorsTile.faceColor;
|
||||
openColors[1] = colorsTile.topColor;
|
||||
openColors[2] = colorsTile.bottomColor;
|
||||
}
|
||||
|
||||
// Set the tile to closed state
|
||||
public void SetTileClosed()
|
||||
{
|
||||
isOpen = false;
|
||||
|
||||
// Hide character
|
||||
if (character != null)
|
||||
{
|
||||
character.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// Apply closed color to all images
|
||||
for (var i = 0; i < images.Length; i++)
|
||||
{
|
||||
var img = images[i];
|
||||
if (img != null)
|
||||
{
|
||||
img.color = closedColors[i];
|
||||
}
|
||||
}
|
||||
|
||||
transform.SetAsFirstSibling();
|
||||
}
|
||||
|
||||
// Set the tile to open state
|
||||
public void SetTileOpen()
|
||||
{
|
||||
isOpen = true;
|
||||
HapticFeedback.TriggerHapticFeedback(HapticFeedback.HapticForce.Light);
|
||||
|
||||
// Show character
|
||||
if (character != null)
|
||||
{
|
||||
character.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
// Apply open color to all images
|
||||
for (var i = 0; i < images.Length; i++)
|
||||
{
|
||||
var img = images[i];
|
||||
if (img != null)
|
||||
{
|
||||
img.color = openColors[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Add bounce animation
|
||||
transform.DOScale(1.2f, 0.1f)
|
||||
.SetEase(Ease.OutQuad)
|
||||
.OnComplete(() => {
|
||||
transform.DOScale(1f, 0.15f)
|
||||
.SetEase(Ease.Linear);
|
||||
});
|
||||
|
||||
transform.SetAsLastSibling();
|
||||
|
||||
// If this tile has a special item, animate it and ensure it stays on top
|
||||
if (hasSpecialItem && specialItemInstance != null)
|
||||
{
|
||||
specialItemInstance.transform.SetAsLastSibling();
|
||||
|
||||
SpecialItem specialItem = specialItemInstance.GetComponent<SpecialItem>();
|
||||
if (specialItem != null)
|
||||
{
|
||||
// Try to find a target position - use level manager collection point if available
|
||||
Vector3 targetPosition = transform.position + new Vector3(0, 300, 0); // Default fallback
|
||||
|
||||
// Get special item collection point if available
|
||||
if (levelManager != null)
|
||||
{
|
||||
var collectionPoint = levelManager.GetSpecialItemCollectionPoint();
|
||||
targetPosition = collectionPoint;
|
||||
}
|
||||
|
||||
// Start the animation
|
||||
specialItem.FlyToPosition(targetPosition, () => {
|
||||
// Notify level manager that item was collected
|
||||
if (levelManager != null)
|
||||
{
|
||||
levelManager.CollectSpecialItem(specialItemPosition);
|
||||
}
|
||||
// Clear the reference since the item destroys itself
|
||||
specialItemInstance = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Check if tile is open
|
||||
public bool IsOpen()
|
||||
{
|
||||
return isOpen;
|
||||
}
|
||||
|
||||
// Set the character for this tile
|
||||
public void SetCharacter(char c)
|
||||
{
|
||||
if (character != null)
|
||||
{
|
||||
character.text = c.ToString().ToUpper();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShakeTile()
|
||||
{
|
||||
RectTransform rectTransform = GetComponent<RectTransform>();
|
||||
if (rectTransform == null)
|
||||
return;
|
||||
|
||||
Vector2 originalPosition = rectTransform.anchoredPosition;
|
||||
|
||||
Sequence shakeSequence = DOTween.Sequence();
|
||||
|
||||
float shakeAmount = 5f;
|
||||
float shakeDuration = 0.05f;
|
||||
int shakeCount = 4;
|
||||
|
||||
for (int i = 0; i < shakeCount; i++)
|
||||
{
|
||||
float xOffset = (i % 2 == 0) ? shakeAmount : -shakeAmount;
|
||||
|
||||
shakeSequence.Append(rectTransform.DOAnchorPos(
|
||||
new Vector2(originalPosition.x + xOffset, originalPosition.y),
|
||||
shakeDuration).SetEase(Ease.OutQuad));
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < images.Length; i++)
|
||||
{
|
||||
if (images[i] != null)
|
||||
{
|
||||
shakeSequence.Join(images[i].DOColor(Color.white, shakeDuration)
|
||||
.SetLoops(2, LoopType.Yoyo));
|
||||
}
|
||||
}
|
||||
shakeSequence.Append(rectTransform.DOAnchorPos(originalPosition, shakeDuration));
|
||||
}
|
||||
|
||||
// Enhanced method to associate a special item with this tile
|
||||
public void AssociateSpecialItem(Vector2Int position)
|
||||
{
|
||||
hasSpecialItem = true;
|
||||
specialItemPosition = position;
|
||||
|
||||
// Create the special item instance if we have a prefab
|
||||
if (specialItemPrefab != null && specialItemInstance == null)
|
||||
{
|
||||
InstantiateSpecialItem();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Associate with a specific prefab (override the default)
|
||||
public void AssociateSpecialItem(Vector2Int position, GameObject itemPrefab)
|
||||
{
|
||||
// Set the prefab
|
||||
specialItemPrefab = itemPrefab;
|
||||
|
||||
// Call the regular association method
|
||||
AssociateSpecialItem(position);
|
||||
}
|
||||
|
||||
// Create the special item instance
|
||||
private void InstantiateSpecialItem()
|
||||
{
|
||||
if (specialItemPrefab == null)
|
||||
{
|
||||
// Try to load a default prefab if none is assigned
|
||||
specialItemPrefab = Resources.Load<GameObject>("Prefabs/DefaultSpecialItem");
|
||||
|
||||
if (specialItemPrefab == null)
|
||||
{
|
||||
Debug.LogWarning("No special item prefab assigned to tile and no default found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
specialItemInstance = objectResolver.Instantiate(specialItemPrefab, transform);
|
||||
specialItemInstance.transform.SetParent(transform.parent);
|
||||
specialItemInstance.transform.SetAsLastSibling();
|
||||
// fit size to tile
|
||||
RectTransform rectTransform = specialItemInstance.GetComponent<RectTransform>();
|
||||
if (rectTransform != null)
|
||||
{
|
||||
rectTransform.sizeDelta = GetComponent<RectTransform>().sizeDelta / 1.2f;
|
||||
}
|
||||
if (levelManager != null)
|
||||
{
|
||||
levelManager.RegisterSpecialItem(specialItemPosition, specialItemInstance);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove special item association and destroy instance
|
||||
public void RemoveSpecialItem()
|
||||
{
|
||||
hasSpecialItem = false;
|
||||
|
||||
if (specialItemInstance != null)
|
||||
{
|
||||
Destroy(specialItemInstance);
|
||||
specialItemInstance = null;
|
||||
}
|
||||
}
|
||||
// Check if this tile has a special item and return its position
|
||||
public bool HasSpecialItem(out Vector2Int position)
|
||||
{
|
||||
position = specialItemPosition;
|
||||
return hasSpecialItem;
|
||||
}
|
||||
|
||||
// Play hammer animation and open tile with delay
|
||||
private void PlayHammerAnimationAndOpen()
|
||||
{
|
||||
if (hammerAnimationPrefab != null)
|
||||
{
|
||||
// Instantiate hammer animation on this tile
|
||||
var offset = Vector3.right * 1.5f + Vector3.up * 0.5f;
|
||||
GameObject hammer = Instantiate(hammerAnimationPrefab, transform.position + offset, Quaternion.identity);
|
||||
DOVirtual.DelayedCall(.6f, OpenTileAfterAnimation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no hammer animation, just open immediately
|
||||
OpenTileAfterAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
// Open the tile after animation completes
|
||||
private void OpenTileAfterAnimation()
|
||||
{
|
||||
SetTileOpen();
|
||||
EventManager.GetEvent<Tile>(EGameEvent.TileSelected).Invoke(this);
|
||||
}
|
||||
|
||||
// Implement UI touch interface method instead of OnMouseDown
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
// Only respond if the tile is selectable and closed
|
||||
if (!isOpen && levelManager != null && levelManager.hammerMode)
|
||||
{
|
||||
// Instead of opening immediately, play hammer animation first
|
||||
PlayHammerAnimationAndOpen();
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillIcon(ScriptableData iconScriptable)
|
||||
{
|
||||
UpdateColor((ColorsTile)iconScriptable);
|
||||
}
|
||||
|
||||
private void UpdateColor(ColorsTile itemTemplate)
|
||||
{
|
||||
images[0].color = itemTemplate.faceColor;
|
||||
images[1].color = itemTemplate.topColor;
|
||||
images[2].color = itemTemplate.bottomColor;
|
||||
}
|
||||
|
||||
public void ShowEffect()
|
||||
{
|
||||
fx.SetActive(true);
|
||||
}
|
||||
|
||||
public GameObject GetSpecialItemInstance()
|
||||
{
|
||||
return specialItemInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user