Unity 2D蛇形游戏传送功能Bug排查求助
Hey there! No worries at all about being a Unity newbie—we all start somewhere, and your question is totally clear even if you feel it's "shallow." Let's break down the bug you're facing with your snake's body behavior after teleporting through walls.
First, from your description and demo, it sounds like the snake's body segments are getting misaligned or behaving erratically right after the head teleports through a wall. Your hunch about the body-following code being the issue is on the mark, but we also need to fix how the teleport interacts with your position history system.
Key Issues Identified
- Unsynced Position History After Teleport: Your
WallTeleportationscript only moves the snake's head, but doesn't update thePositionHistorythat body segments rely on. When the head jumps to the other side of the screen, the body still tries to follow the old pre-teleport path, causing weird jumps or misalignment. - 3D Rotation Method in 2D Context: Using
Quaternion.LookRotation(a 3D method) for 2D rotation can lead to unexpected behavior, especially when the head's position suddenly flips. A 2D-specific rotation calculation will be more reliable. - Unbounded Position History: Without limiting the length of
PositionHistory, you might end up with a huge list over time, causing performance issues and making the body follow outdated positions longer than needed.
Fixes to Implement
1. Update Teleport Script to Sync Position History
Modify your WallTeleportation code to reset the position history when the head teleports, so the body starts following the new path immediately:
private void OnTriggerEnter2D(Collider2D col) { if (col.gameObject.layer == 6) { Debug.Log("GameObject1 collided with " + col.transform.position); // Get the snake movement component from the head SnakeMovement snake = col.GetComponent<SnakeMovement>(); if (snake != null) { // Clear old history to avoid body chasing outdated positions snake.PositionHistory.Clear(); // Add the current (pre-teleport) position first snake.PositionHistory.Insert(0, col.transform.position); } // Perform the teleport col.transform.position = new Vector3(col.transform.position.x, col.transform.position.y * -1, 0); if (snake != null) { // Add the new teleport position to the top of the history snake.PositionHistory.Insert(0, col.transform.position); } } }
2. Refine Body Following & Rotation Code
Replace your body loop in SnakeMovement.Update() with this 2D-friendly version, using smooth movement and proper rotation:
int index = 0; foreach (var body in BodyParts) { // Calculate the target position from history, ensuring we don't go out of bounds int historyIndex = Mathf.Min(index * Gap, PositionHistory.Count - 1); Vector3 targetPoint = PositionHistory[historyIndex]; // Use Vector3.MoveTowards for smoother, more controlled movement body.transform.position = Vector3.MoveTowards(body.transform.position, targetPoint, BodySpeed * Time.deltaTime); // Calculate 2D rotation using Atan2 (more reliable for 2D than LookRotation) Vector3 directionToHead = transform.position - body.transform.position; float rotationAngle = Mathf.Atan2(directionToHead.y, directionToHead.x) * Mathf.Rad2Deg - 90f; // Adjust the -90f to match your sprite's default orientation body.transform.rotation = Quaternion.Euler(0, 0, rotationAngle); index++; }
3. Limit Position History Length
Add this right after inserting the new position in SnakeMovement.Update() to prevent memory bloat:
PositionHistory.Insert(0, transform.position); // Keep history length reasonable (adjust the +20 buffer as needed) if (PositionHistory.Count > BodyParts.Count * Gap + 20) { PositionHistory.RemoveAt(PositionHistory.Count - 1); }
4. Improve New Body Segment Spawning
Update your waiter coroutine to spawn new body segments at a logical position, so they don't pop in unexpectedly:
IEnumerator waiter() { GameObject body = Instantiate(BodyPrefab); body.SetActive(false); // Spawn new body at the last body's position (or head position if no bodies exist) if (BodyParts.Count > 0) { body.transform.position = BodyParts.Last().transform.position; } else { body.transform.position = transform.position; } BodyParts.Add(body); yield return new WaitForSeconds(0.2f); body.SetActive(true); }
Why This Works
By resetting the position history during teleport, you're telling the body segments to start following the head's new path immediately. The 2D rotation method ensures the body faces the head correctly even after position flips, and limiting history length keeps the system efficient.
Give these changes a try—they should resolve the weird body behavior you're seeing!
内容的提问来源于stack exchange,提问作者Evgeniy Mokrushin

