Unity中基于C#的网格移动(含碰撞检测)实现及宝可梦风格游戏开发学习资源咨询
Hey there! Let's break down your problem step by step— I know how frustrating it can be when tutorial code doesn't work as expected, especially when you're just starting out with grid-based movement like Pokémon in Unity.
First: Fix Your Broken Code
Looking at your script, there are two critical issues that are making it fail completely:
- All directions are set to
Vector3.up: You're using the same direction for W/A/S/D—so no matter which key you press, the player only moves up. - Typo in coroutine call: You wrote
StartCoroutine/(...)instead ofStartCoroutine(...)(slash instead of parentheses).
Here's the corrected base version of your code, with proper direction mapping:
using System.Collections; using UnityEngine; public class GridMovement : MonoBehaviour { private bool isMoving; private Vector3 origPos, targetPos; private float timeToMove = 0.2f; // Define your grid cell size (usually 1 unit for top-down Pokémon style) public float gridCellSize = 1f; void Update() { if (isMoving) return; // Skip input if already moving if (Input.GetKeyDown(KeyCode.W)) StartCoroutine(MovePlayer(Vector3.forward * gridCellSize)); if (Input.GetKeyDown(KeyCode.A)) StartCoroutine(MovePlayer(Vector3.left * gridCellSize)); if (Input.GetKeyDown(KeyCode.S)) StartCoroutine(MovePlayer(Vector3.back * gridCellSize)); if (Input.GetKeyDown(KeyCode.D)) StartCoroutine(MovePlayer(Vector3.right * gridCellSize)); } private IEnumerator MovePlayer(Vector3 direction) { isMoving = true; float elapsedTime = 0; origPos = transform.position; targetPos = origPos + direction; while (elapsedTime < timeToMove) { transform.position = Vector3.Lerp(origPos, targetPos, elapsedTime / timeToMove); elapsedTime += Time.deltaTime; yield return null; } transform.position = targetPos; isMoving = false; } }
Note: I switched GetKey to GetKeyDown so the player moves once per key press, not continuously—this is more true to Pokémon's movement style.
Adding Collision Detection
To stop the player from moving through walls/obstacles, we need to check if the target position is clear before starting the movement. Here's how to add that:
- Set up layers: Create an "Obstacles" layer in Unity and assign all your wall/block objects to it.
- Add collision check logic: Modify the script to validate the target position before moving.
Updated code with collision detection:
using System.Collections; using UnityEngine; public class GridMovement : MonoBehaviour { private bool isMoving; private Vector3 origPos, targetPos; private float timeToMove = 0.2f; public float gridCellSize = 1f; // Assign your Obstacles layer here in the Inspector public LayerMask obstacleLayer; void Update() { if (isMoving) return; if (Input.GetKeyDown(KeyCode.W)) AttemptMove(Vector3.forward * gridCellSize); if (Input.GetKeyDown(KeyCode.A)) AttemptMove(Vector3.left * gridCellSize); if (Input.GetKeyDown(KeyCode.S)) AttemptMove(Vector3.back * gridCellSize); if (Input.GetKeyDown(KeyCode.D)) AttemptMove(Vector3.right * gridCellSize); } private void AttemptMove(Vector3 direction) { targetPos = transform.position + direction; // Check if target position is free of obstacles if (IsPositionClear(targetPos)) { StartCoroutine(MovePlayer(direction)); } } private bool IsPositionClear(Vector3 position) { // Use OverlapBox to check for collisions at the target position // Adjust the box size to match your player's collider Collider[] hitColliders = Physics.OverlapBox(position, transform.localScale / 2, Quaternion.identity, obstacleLayer); return hitColliders.Length == 0; } private IEnumerator MovePlayer(Vector3 direction) { isMoving = true; float elapsedTime = 0; origPos = transform.position; targetPos = origPos + direction; while (elapsedTime < timeToMove) { transform.position = Vector3.Lerp(origPos, targetPos, elapsedTime / timeToMove); elapsedTime += Time.deltaTime; yield return null; } transform.position = targetPos; isMoving = false; } }
Make sure your player has a collider (like a BoxCollider) and that obstacle objects have colliders set to "Is Trigger" disabled.
Reliable Learning Resources for Pokémon-Style Games
Since you mentioned struggling with unhelpful tutorials, here are some trustworthy places to learn (all within Unity's ecosystem or well-respected developer communities):
- Unity Learn Official Tutorials: The official Unity Learn platform has a dedicated 2D RPG series that covers grid movement, collision, and other core systems similar to Pokémon. Look for courses tagged "Grid-Based Movement" or "2D RPG".
- Unity Forums: The official Unity Forums have a dedicated "Game Development" section where you can ask specific questions, and many experienced developers share step-by-step guides for grid movement systems.
- Unity Asset Store Sample Projects: Some free sample projects on the Asset Store focus on top-down grid-based games—downloading these lets you dissect working code and see how professionals implement movement and collision.
- Curated YouTube Creator Series: Look for creators who specialize in Unity 2D tutorials and have a track record of clear, tested code (avoid one-off videos with untested scripts). Many creators break down Pokémon-style systems piece by piece, from movement to battle mechanics.
Final Tips for Beginners
- Start small: Don't try to build the entire Pokémon game at once. Focus on getting movement working first, then add collision, then NPC interactions, etc.
- Use debug tools: Unity's
Debug.DrawRayorDebug.DrawCubecan help you visualize your collision checks and make sure your target positions are correct. - Read Unity's official documentation: The docs for
Physics.OverlapBox,Coroutines, andVector3are your best friends—they explain exactly how each function works and give examples.
内容的提问来源于stack exchange,提问作者cireon




