Unity3d+C#开发智龙迷城复刻版:符文拖拽交换功能实现求助
Hey there! I’ve built similar match-3 drag mechanics in Unity before, so let’s walk through practical steps to get your rune swap working smoothly.
1. Core Setup: Rune Script with Drag Interfaces
First, attach a script to your rune prefab that uses Unity’s event interfaces to handle drag start, movement, and end. This works for both 2D and 3D runes—just adjust the raycasting type later.
using UnityEngine; using UnityEngine.EventSystems; public class Rune : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { private Vector3 _startPosition; private Transform _originalParent; private Rune _targetRune; private CanvasGroup _canvasGroup; void Awake() { _canvasGroup = GetComponent<CanvasGroup>(); } public void OnBeginDrag(PointerEventData eventData) { // Store initial state and move rune to overlay for proper rendering _startPosition = transform.position; _originalParent = transform.parent; transform.SetParent(FindObjectOfType<Canvas>().transform); _canvasGroup.blocksRaycasts = false; // Prevent blocking other raycasts while dragging } public void OnDrag(PointerEventData eventData) { // Follow mouse position during drag transform.position = Input.mousePosition; } public void OnEndDrag(PointerEventData eventData) { // Reset parent and raycast blocking transform.SetParent(_originalParent); _canvasGroup.blocksRaycasts = true; // Raycast to find the target rune we're dropping onto if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out RaycastHit hit)) { _targetRune = hit.collider.GetComponent<Rune>(); if (_targetRune != null && IsAdjacent(_targetRune)) { // Swap positions with the adjacent rune StartCoroutine(AnimateSwap(_targetRune)); // Check if swap creates a match (implement your match logic here) if (!CheckForMatches()) { // No match? Swap back immediately StartCoroutine(AnimateSwap(_targetRune)); } } else { // No valid target, snap back to original position transform.position = _startPosition; } } else { transform.position = _startPosition; } } // Check if the target rune is adjacent on the grid private bool IsAdjacent(Rune otherRune) { // Adjust the 1.1f value to match your grid cell size Vector3 positionDiff = transform.position - otherRune.transform.position; return (Mathf.Abs(positionDiff.x) < 1.1f && Mathf.Abs(positionDiff.y) < 0.1f) || (Mathf.Abs(positionDiff.y) < 1.1f && Mathf.Abs(positionDiff.x) < 0.1f); } // Smooth animation for swap movement private IEnumerator AnimateSwap(Rune otherRune) { Vector3 myStartPos = transform.position; Vector3 targetStartPos = otherRune.transform.position; float duration = 0.15f; float elapsedTime = 0f; while (elapsedTime < duration) { elapsedTime += Time.deltaTime; float t = elapsedTime / duration; transform.position = Vector3.Lerp(myStartPos, targetStartPos, t); otherRune.transform.position = Vector3.Lerp(targetStartPos, myStartPos, t); yield return null; } // Ensure positions are exact after animation transform.position = targetStartPos; otherRune.transform.position = myStartPos; } // Replace this with your actual match detection logic private bool CheckForMatches() { // Example: Check 3+ runes in a row/column // Return true if matches are found, false otherwise return false; } }
2. Scene Configuration
- Add a
CanvasGroupcomponent to your rune prefab (setInteractabletotrueandBlocks Raycaststotrueinitially). - Ensure your runes have a collider (like
BoxColliderorSphereCollider) so raycasts can detect them. - Verify your
EventSystemhas aPhysicsRaycaster(for 3D) orGraphicRaycaster(for UI) component—this is critical for detecting drag events.
3. Grid Alignment (Optional but Recommended)
For Puzzle & Dragons’ strict grid, assign each rune a grid coordinate (e.g., (x, y)). This makes adjacency checks and match detection way easier. Add a GridManager script to track runes:
public class GridManager : MonoBehaviour { public int gridWidth = 5; public int gridHeight = 6; public float cellSize = 1f; private Rune[,] _grid; void Start() { _grid = new Rune[gridWidth, gridHeight]; // Populate the grid with your spawned runes here } public Rune GetRuneAt(int x, int y) { if (x >= 0 && x < gridWidth && y >= 0 && y < gridHeight) return _grid[x, y]; return null; } public void UpdateGridPosition(Rune rune, int oldX, int oldY, int newX, int newY) { _grid[oldX, oldY] = null; _grid[newX, newY] = rune; } }
Modify your Rune script to track its (x, y) grid position and use GridManager for adjacency checks instead of world positions.
Troubleshooting Quick Fixes
- Drag not registering? Double-check colliders, raycasters, and
CanvasGroupsettings. - Runes not snapping to grid? Verify your grid coordinate calculation logic.
- Swap not rolling back? Test your
CheckForMatchesfunction with hardcoded values first to ensure it works.
Let me know if you need help refining any part of this—match-3 mechanics can be tricky, but this foundation should get you over the hump!
内容的提问来源于stack exchange,提问作者Arcosha

