En aquest projecte, implementarem una navegació bàsica per a un personatge no jugador (NPC) en un entorn de joc. Utilitzarem l'algoritme A* per a la cerca de camins i NavMesh per a la navegació. Aquest projecte està dissenyat per consolidar els coneixements adquirits en el Mòdul 2.

Objectius del Projecte

  • Implementar l'algoritme A* per a la cerca de camins.
  • Utilitzar NavMesh per a la navegació del NPC.
  • Integrar l'evitació d'obstacles en la navegació.

Requisits Previs

  • Coneixements bàsics de programació en un llenguatge com C# o Python.
  • Familiaritat amb un motor de joc com Unity o Unreal Engine.
  • Comprensió dels conceptes de navegació i cerca de camins.

Passos del Projecte

  1. Configuració de l'Entorn de Desenvolupament

  1. Instal·lar Unity/Unreal Engine: Assegura't de tenir instal·lat el motor de joc que utilitzaràs.
  2. Crear un Nou Projecte: Crea un projecte nou i configura l'escena bàsica amb un terreny i alguns obstacles.

  1. Implementació de l'Algoritme A*

  1. Definir la Graella de Navegació: Crea una graella que representi l'entorn de joc.
  2. Implementar l'Algoritme A*: Escriu el codi per a l'algoritme A* que trobarà el camí més curt entre dos punts.

Exemple de Codi en C# (Unity)

using System.Collections.Generic;
using UnityEngine;

public class AStarPathfinding : MonoBehaviour
{
    public Transform startNode, endNode;
    private List<Node> openList, closedList;
    private Node[,] grid;

    void Start()
    {
        // Inicialitzar la graella i els nodes
        InitializeGrid();
        FindPath(startNode.position, endNode.position);
    }

    void InitializeGrid()
    {
        // Inicialitzar la graella amb nodes
        // ...
    }

    void FindPath(Vector3 startPos, Vector3 endPos)
    {
        Node startNode = GetNodeFromPosition(startPos);
        Node endNode = GetNodeFromPosition(endPos);

        openList = new List<Node> { startNode };
        closedList = new List<Node>();

        while (openList.Count > 0)
        {
            Node currentNode = openList[0];
            for (int i = 1; i < openList.Count; i++)
            {
                if (openList[i].FCost < currentNode.FCost || openList[i].FCost == currentNode.FCost && openList[i].hCost < currentNode.hCost)
                {
                    currentNode = openList[i];
                }
            }

            openList.Remove(currentNode);
            closedList.Add(currentNode);

            if (currentNode == endNode)
            {
                RetracePath(startNode, endNode);
                return;
            }

            foreach (Node neighbor in GetNeighbors(currentNode))
            {
                if (!neighbor.walkable || closedList.Contains(neighbor))
                {
                    continue;
                }

                int newCostToNeighbor = currentNode.gCost + GetDistance(currentNode, neighbor);
                if (newCostToNeighbor < neighbor.gCost || !openList.Contains(neighbor))
                {
                    neighbor.gCost = newCostToNeighbor;
                    neighbor.hCost = GetDistance(neighbor, endNode);
                    neighbor.parent = currentNode;

                    if (!openList.Contains(neighbor))
                    {
                        openList.Add(neighbor);
                    }
                }
            }
        }
    }

    void RetracePath(Node startNode, Node endNode)
    {
        List<Node> path = new List<Node>();
        Node currentNode = endNode;

        while (currentNode != startNode)
        {
            path.Add(currentNode);
            currentNode = currentNode.parent;
        }
        path.Reverse();

        // Assignar el camí al NPC
        // ...
    }

    int GetDistance(Node nodeA, Node nodeB)
    {
        int dstX = Mathf.Abs(nodeA.gridX - nodeB.gridX);
        int dstY = Mathf.Abs(nodeA.gridY - nodeB.gridY);

        if (dstX > dstY)
            return 14 * dstY + 10 * (dstX - dstY);
        return 14 * dstX + 10 * (dstY - dstX);
    }

    Node GetNodeFromPosition(Vector3 position)
    {
        // Convertir la posició a un node de la graella
        // ...
    }

    List<Node> GetNeighbors(Node node)
    {
        // Obtenir els nodes veïns
        // ...
    }
}

  1. Navegació amb NavMesh

  1. Configurar NavMesh: Utilitza les eines del motor de joc per generar un NavMesh a l'entorn.
  2. Assignar NavMesh Agent al NPC: Afegeix un component NavMesh Agent al NPC per permetre-li navegar pel NavMesh.

Exemple de Configuració en Unity

using UnityEngine;
using UnityEngine.AI;

public class NPCNavigation : MonoBehaviour
{
    public Transform target;

    private NavMeshAgent agent;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        agent.SetDestination(target.position);
    }

    void Update()
    {
        if (Vector3.Distance(transform.position, target.position) < 1.0f)
        {
            // Arribat a la destinació
            // ...
        }
    }
}

  1. Evitació d'Obstacles

  1. Configurar Obstacles: Afegeix obstacles a l'escena i assegura't que el NavMesh els tingui en compte.
  2. Ajustar Paràmetres del NavMesh Agent: Modifica els paràmetres del NavMesh Agent per millorar l'evitació d'obstacles.

  1. Proves i Depuració

  1. Provar la Navegació: Executa el joc i verifica que el NPC pot navegar correctament fins a la destinació.
  2. Depurar Problemes: Si el NPC no es mou correctament, revisa el codi i els paràmetres del NavMesh Agent.

Exercicis Pràctics

  1. Modificar l'Entorn: Afegeix més obstacles i comprova com afecta la navegació del NPC.
  2. Canviar la Destinació: Implementa un sistema per canviar la destinació del NPC durant el joc.
  3. Millorar l'Evitació d'Obstacles: Ajusta els paràmetres del NavMesh Agent per millorar l'evitació d'obstacles en diferents situacions.

Solucions als Exercicis

  1. Modificar l'Entorn: Afegeix obstacles a l'escena i regenera el NavMesh. Verifica que el NPC pot trobar un nou camí evitant els obstacles.
  2. Canviar la Destinació: Afegeix un script que permeti canviar la destinació del NPC en resposta a esdeveniments del joc, com ara clics del ratolí.
  3. Millorar l'Evitació d'Obstacles: Experimenta amb els paràmetres avoidancePriority, radius, i speed del NavMesh Agent per trobar la configuració òptima.

Conclusió

En aquest projecte, hem implementat una navegació bàsica per a un NPC utilitzant l'algoritme A* i NavMesh. Hem après a configurar l'entorn de desenvolupament, implementar l'algoritme de cerca de camins, utilitzar NavMesh per a la navegació i integrar l'evitació d'obstacles. Aquestes habilitats són fonamentals per al desenvolupament de comportaments intel·ligents en els personatges dels videojocs.

En el següent projecte, aplicarem aquests coneixements per crear un NPC amb presa de decisions utilitzant màquines d'estats finits i arbres de decisió.

© Copyright 2024. Tots els drets reservats