Introducción

1

Game Design del juego

2

La estructura y assets de un proyecto en Unity

3

Convirtiendo nuestros assets en Tiles

4

Tilemaps y creación del escenario

5

Bonus: FastForward de la creación del escenario, sorting layers y creación de colliders

6

Acá encontrarás los archivos de este curso

Personaje principal: Movimiento y Animaciones

7

El jugador y el movimiento

8

Creando nuestra primera animación

9

Creando el grafo de animaciones

10

Usando un árbol de animaciones

11

Mostrando la solución del desafío e implementando transición entre blended trees

12

Programando una cámara que siga al jugador

13

Corrección del bug gráfico

14

límites del escenario, rigid bodies

15

Ejercicio: diseño de interiores

Escenarios Avanzados

16

Transiciones entre escenas

17

Mantener Player y Camera entre escenas

18

Spawning Points: programando que el jugador y la cámara aparezcan en el lugar correcto al cambiar de escena

19

Agregando Identificadores a nuestros Spawning Points para controlar mejor el flujo de nuestro juego

Enemigos Avanzados

20

Creando nuestro enemigo

21

Programando las físicas y el patrullaje del enemigo

22

Generando movimiento completamente aleatorio

23

Programando el ataque del enemigo

24

Crear Manager de Health del Player

25

Crear armas

26

Programando el ataque del Player con arma

27

Mover la espada al caminar

28

Creando el ataque con espada

29

Ejecutando el ataque con un botón

30

Movimiento en diagonal

31

Optimizando nuestro player controller

32

Ataque mejorado

33

Uso de partículas

34

Añadir el daño del enemigo en batalla

35

Programando los contadores de vida del enemigo

36

Colocando más info de UI en pantalla

37

Script de la vida

Personaje principal avanzado

38

Añadir el daño del personaje (ejercicio)

39

Sistema de puntos de experiencia para nuestro personaje principal

40

Level Up!

41

Level Up! Defensa y Reto Final del Módulo: Stats de los enemigos

42

Creando un NPC

43

Limitar el movimiento de nuestro NPC

44

Creando una pantalla de diálogos para nuestro RPG

45

El diálogo del NPC

46

Múltiples líneas de diálogo

47

Parar el NPC durante el diálogo

48

Parar el personaje durante el diálogo

Quests

49

La estructura de una quest

50

Quest 1: Ir a un lugar

51

Quest 2: Encontrar un objeto

52

Quest 3: Matar enemigos

53

Revisión de bugs

54

Mantener la cámara dentro del escenario

55

El problema al cambiar de escena

Audio

56

Agregando SFX a nuestro videojuego

57

Agregando música a nuestro videojuego

58

Ajustar volúmen del audio de cada uno de los efectos de sonido

59

Creando un VolumeManager

60

Agregando economía a nuestro juego y cierre

Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Limitar el movimiento de nuestro NPC

43/60
Recursos

Aportes 7

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Hola Juan/Comunidad, ami esta lógica no me sirvió, tengo al NPC solo (sin que lo muevan enemigos) y aun así se va de la zona, lo único que hace es que cada vez que esta por salir de la zona lo para, pero luego sigue caminando aleatoriamente y en algún momento termina saliendo. Se que explicarlo con palabras o imágenes puede ser difícil, acá les dejo un video donde muestro el código y el error. Video

Buenas a todos!

Me gustaria compartir el codigo que me sirvio para que hacer que el npc se dirija a un punto aleatorio dentro de los limites de la zona del npc cuando llega a uno de los limites de la zona:

<
if(NPC_zone != null)
            {
                if(this.transform.position.x < NPC_zone.bounds.min.x ||
                   this.transform.position.x > NPC_zone.bounds.max.x ||
                   this.transform.position.y < NPC_zone.bounds.min.y ||
                   this.transform.position.y > NPC_zone.bounds.max.y)
                {
                    //StopWalking();

                    // Obtiene un vector que apunta desde la posición del npc a un punto aleatorio dentro de los limites de la zona del NPC.
                    directionToMakeStep = (new Vector3(Random.Range(NPC_zone.bounds.min.x, NPC_zone.bounds.max.x), Random.Range(NPC_zone.bounds.min.y, NPC_zone.bounds.max.y), NPC_zone.bounds.min.z) - this.transform.position).normalized * enemySpeed;
                }
            }
            	
>

Esta fue mi solucion utilizando el metodo clamp, simplemente hay que añadir este script al presonaje que se quiere dentro del perimetro, y hacemos referencia al boxcollider2D arrastrando. Esto funciona ya que Unity al hacer Update suma el resultado de todos los vectores.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Boundaries : MonoBehaviour
{
    public BoxCollider2D npcDelimitedZone;
    private void Update() {
        this.transform.position = new Vector3(Mathf.Clamp(this.transform.position.x, npcDelimitedZone.bounds.min.x, npcDelimitedZone.bounds.max.x),
                                                Mathf.Clamp(this.transform.position.y, npcDelimitedZone.bounds.min.y, npcDelimitedZone.bounds.max.y),
                                                this.transform.position.z);
                                                
    }

}

Aquí parte del código:

 if (villagerZone != null)
        {
            //Comprobamos por cual lado esta saliendo el npc de su box.
            if (this.transform.position.x > villagerZone.bounds.max.x || this.transform.position.x < villagerZone.bounds.min.x ||
                this.transform.position.y > villagerZone.bounds.max.y || this.transform.position.y < villagerZone.bounds.min.y)
            {
                //Lo detenemos de caminar.
                StopWalking();
            }
        }```

Comparto como hice esta parte

Dentro de StopMovement la primer linea hago isMoving = false asi no tiene un comportamiento raro.

if (isMoving) {
            StartMovement();
            if(movementZone && isOutsideZone())
                StopMovement();
        } else {
            StopMovement();
        }

La funcion isOutsideZone compara la posicion del personaje con la zona pero me pareció mas legible con la funcion 😉

Para que el enemigo no choque con el NPC, lo que se hace es marcar el NPC con un layer:

Y hacer lo mismo con el enemigo, marcarlo con un layer Enemy:

Despues en project settings se deselecciona la interaccion NPC - Enemy:

Les comparto mi solucion, le agregue una variable llamada latestDirection, esto con el fin que cuando el NPC toque un boundary, el currentDirection no vuelva a ser el que llevaba cuando toco el boundary. Adicional cuando el NPC toca el boundary, lo que hago es que lo hago devolver a la direccion contraria.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NPCMovement : MonoBehaviour
{
    public float speed = 1.5f;
    private Rigidbody2D npcRigidbody;
    
    public bool isWalking;

    public float walkTime = 1.5f;
    public float walkCounter;
    
    public float waitTime = 3.0f;
    public float waitCounter;

    public bool zoneBoundaryReached = false;

    public Vector2[] walkingDirection =
    {
        new Vector2(-1,0),
        new Vector2(1,0),
        new Vector2(0,-1),
        new Vector2(0,1)
    };

    public int currentDirection = 0;
    public int latestDirection = 0;

    [SerializeField] BoxCollider2D villagerZone;

    // Start is called before the first frame update
    void Start()
    {
        npcRigidbody = GetComponent<Rigidbody2D>();
        waitCounter = waitTime;
        walkCounter = walkTime;

    }

    // Update is called once per frame
    void Update()
    {
        if (isWalking)
        {
            if (villagerZone != null)
            {
                if (this.transform.position.x <= villagerZone.bounds.min.x || this.transform.position.x >= villagerZone.bounds.max.x ||
                    this.transform.position.y <= villagerZone.bounds.min.y || this.transform.position.y >= villagerZone.bounds.max.y)
                {
                    if (currentDirection == 1 || currentDirection == 3)
                    {
                        currentDirection--;
                    }
                    else
                        currentDirection++;
                }
            }

            npcRigidbody.velocity = walkingDirection[currentDirection] * speed;

            walkCounter -= Time.deltaTime;
            if (walkCounter < 0)
            {
                if (zoneBoundaryReached)
                    zoneBoundaryReached = false;
                StopWalking();
            }
        }
        else
        {
            npcRigidbody.velocity = Vector2.zero;

            waitCounter -= Time.deltaTime;
            if (waitCounter < 0)
            {
                StartWalking();
            }
        }
    }

    private void StartWalking()
    {
        isWalking = true;
        while (latestDirection == currentDirection)
            currentDirection = Random.Range(0, 4);
        latestDirection = currentDirection;
        walkCounter = walkTime;
    }

    private void StopWalking()
    {
        isWalking = false;
        waitCounter = waitTime;
        npcRigidbody.velocity = Vector2.zero;
    }
}