You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

2D类Train Valley游戏铁路路径排序问题技术求助

Alright, let's tackle this path generation issue you're facing with your Train Valley-style grid-based railway game. The core problem here is that using a simple List<Vector3> to store waypoints doesn't account for the topological connection of your railway nodes—when you fill in a skipped cell later, the list's linear order breaks, and your train has no way to understand the actual track layout.

Here are two practical solutions to fix this, along with code adjustments tailored to your existing setup:

Solution 1: Switch to a Graph-Based Node System (Best for Complex Rail Networks)

Instead of relying on a rigid ordered list, model your railway as a graph where each TrainCell knows its adjacent track nodes. This lets you dynamically generate paths based on actual connections, no matter the order you place tracks in.

Step 1: Update the TrainCell Class

Add adjacency tracking to your TrainCell to store connected nodes:

public class TrainCell : MonoBehaviour {
    // Keep your existing properties (CurrentChildIndex, used, etc.)
    public List<TrainCell> adjacentTrackCells = new List<TrainCell>();
}

Step 2: Build Adjacency Relationships When Placing Tracks

When a player places a track cell, automatically detect and link it to neighboring active tracks. Adjust the direction check based on your track types (straight, curved, etc.):

// Insert this in your OnCellClickEvent method, right after marking target.used = true
if (target.used) {
    // Check all 4 cardinal directions (adjust for diagonal tracks if needed)
    TrainCell[] neighboringCells = GetAdjacentTrainCells(target);
    
    foreach (var neighbor in neighboringCells) {
        if (neighbor != null && neighbor.used && !target.adjacentTrackCells.Contains(neighbor)) {
            // Bidirectional link: add each cell to the other's adjacency list
            target.adjacentTrackCells.Add(neighbor);
            neighbor.adjacentTrackCells.Add(target);
        }
    }
}

// Helper method to get adjacent grid cells (implement based on your grid system)
private TrainCell[] GetAdjacentTrainCells(TrainCell target) {
    // Example: replace with your grid's logic to fetch up/down/left/right cells
    return new TrainCell[] {
        GetCellAtPosition(target.transform.position + Vector3.up),
        GetCellAtPosition(target.transform.position + Vector3.down),
        GetCellAtPosition(target.transform.position + Vector3.left),
        GetCellAtPosition(target.transform.position + Vector3.right)
    };
}

Step 3: Generate Paths Dynamically with Graph Traversal

Use a BFS (Breadth-First Search) to find the correct path between stations whenever a train needs to travel. This ensures you always get the latest valid route, even after modifying tracks:

public List<Vector3> GenerateTrainPath(TrainCell startStation, TrainCell endStation) {
    Queue<TrainCell> searchQueue = new Queue<TrainCell>();
    Dictionary<TrainCell, TrainCell> pathHistory = new Dictionary<TrainCell, TrainCell>();
    
    searchQueue.Enqueue(startStation);
    pathHistory[startStation] = null;

    while (searchQueue.Count > 0) {
        TrainCell current = searchQueue.Dequeue();
        
        if (current == endStation) break; // Found our destination
        
        foreach (var neighbor in current.adjacentTrackCells) {
            if (!pathHistory.ContainsKey(neighbor)) {
                pathHistory[neighbor] = current;
                searchQueue.Enqueue(neighbor);
            }
        }
    }

    // Reconstruct the path by backtracking from end to start
    List<Vector3> finalPath = new List<Vector3>();
    TrainCell currentCell = endStation;
    
    while (currentCell != null) {
        // Add the cell's position first
        finalPath.Add(currentCell.transform.position);
        // Add any child waypoints (for curved tracks)
        foreach (Transform child in currentCell.CurrentChild.transform) {
            finalPath.Add(child.position);
        }
        currentCell = pathHistory[currentCell];
    }
    
    finalPath.Reverse(); // Reverse to get start-to-end order
    return finalPath;
}
Solution 2: Linked List for Linear Railways (Simpler for Single-Line Tracks)

If your game focuses mostly on linear tracks (like early Train Valley levels), a doubly linked list can maintain order even when filling gaps.

Step 1: Add Linked List Pointers to TrainCell

public class TrainCell : MonoBehaviour {
    // Existing properties...
    public TrainCell previousCell;
    public TrainCell nextCell;
}

Step 2: Insert New Cells Into the Linked List

When placing a track in a gap, find the adjacent cells that should connect to it and update the pointers:

// In your track placement logic
TrainCell leftNeighbor = GetCellAtPosition(target.transform.position + Vector3.left);
TrainCell rightNeighbor = GetCellAtPosition(target.transform.position + Vector3.right);

// Link to left neighbor if it exists and has no next cell
if (leftNeighbor != null && leftNeighbor.used && leftNeighbor.nextCell == null) {
    leftNeighbor.nextCell = target;
    target.previousCell = leftNeighbor;
}

// Link to right neighbor if it exists and has no previous cell
if (rightNeighbor != null && rightNeighbor.used && rightNeighbor.previousCell == null) {
    rightNeighbor.previousCell = target;
    target.nextCell = rightNeighbor;
}

Step 3: Generate Path by Traversing the Linked List

public List<Vector3> GenerateLinearPath(TrainCell start) {
    List<Vector3> path = new List<Vector3>();
    TrainCell current = start;
    
    while (current != null) {
        path.Add(current.transform.position);
        foreach (Transform child in current.CurrentChild.transform) {
            path.Add(child.position);
        }
        current = current.nextCell;
    }
    
    return path;
}
Key Adjustments to Your Existing Code
  • Remove all direct operations on the WayPoints list—instead, generate paths dynamically using one of the methods above when a train needs to start its route.
  • When deleting tracks, make sure to clean up adjacency lists or linked list pointers (e.g., if you delete a cell, update its neighbors to remove references to it).
  • For curved tracks, keep adding child waypoints to the final path as you already do—just attach them to the corresponding node's data instead of a global list.

内容的提问来源于stack exchange,提问作者Gheorghe C.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:48:02