I am making a 2D top-down RPG. I have animals placed on the terrain at random locations; currently, they are just pacing back and forth. This is pretty boring, so I felt like using something like the wander script from the Unity Community Wiki. Unfortunately, this requires a 3D character controller. Any ideas on getting around this? Thanks!
For a top-down 2D game you can simplify the code to work for you. Iâm assuming movement is limited to 4 directions, right?
So this is how I would make a simple wanderer code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// This makes an object move randomly in a set of directions, with some random time delay in between each decision
/// </summary>
public class Wanderer : MonoBehaviour
{
internal Transform thisTransform;
// The movement speed of the object
public float moveSpeed = 0.2f;
// A minimum and maximum time delay for taking a decision, choosing a direction to move in
public Vector2 decisionTime = new Vector2(1, 4);
internal float decisionTimeCount = 0;
// The possible directions that the object can move int, right, left, up, down, and zero for staying in place. I added zero twice to give a bigger chance if it happening than other directions
internal Vector3[] moveDirections = new Vector3[] { Vector3.right, Vector3.left, Vector3.forward, Vector3.back, Vector3.zero, Vector3.zero };
internal int currentMoveDirection;
// Use this for initialization
void Start()
{
// Cache the transform for quicker access
thisTransform = this.transform;
// Set a random time delay for taking a decision ( changing direction, or standing in place for a while )
decisionTimeCount = Random.Range(decisionTime.x, decisionTime.y);
// Choose a movement direction, or stay in place
ChooseMoveDirection();
}
// Update is called once per frame
void Update()
{
// Move the object in the chosen direction at the set speed
thisTransform.position += moveDirections[currentMoveDirection] * Time.deltaTime * moveSpeed;
if (decisionTimeCount > 0) decisionTimeCount -= Time.deltaTime;
else
{
// Choose a random time delay for taking a decision ( changing direction, or standing in place for a while )
decisionTimeCount = Random.Range(decisionTime.x, decisionTime.y);
// Choose a movement direction, or stay in place
ChooseMoveDirection();
}
}
void ChooseMoveDirection()
{
// Choose whether to move sideways or up/down
currentMoveDirection = Mathf.FloorToInt(Random.Range(0, moveDirections.Length));
}
}
You can freely set any array of directions so itâs not limited to 2D space ( you can make the character move upwards for example). You can make it move in 8 directions too.
For a 2D top-down game you can also expand it to have a set of Sprites that are switched based on the direction you choose, as well as an area Rect limit to make sure the cow only wanders within the intended area and doesnât go far off.
Thanks a bunch! I already have all my animations rigged with xMove and yMove blend tree variables, which shouldnât be too hard to integrate with the script. Iâll post how it comes out.
Iâm trying to use this script to make an NPC âwanderâ in my 2D top down game. However the NPC object only moves along the X access, it never moves along the Y access (up and down).
Any ideas why?
Olly
âAny ideas why?â
Didnât check the code but a general hint;
2D works on XY plane (most often in Unity), whereas ground plane in 3D (in Unity) is oriented along XZ plane.
Try to switch these direction values with ones that fit your plane axis
internal Vector3[ ] moveDirections = new Vector3[ ] { Vector3.right, Vector3.left, Vector3.forward, Vector3.back, Vector3.zero, Vector3.zero }
instead of Vector3.forward and Vector3.back, try to use Vector3.up and Vector3.down and see how it behaves
Heyo, so i want to apply a movement animation to the npc when he walks, but iâve been struggling as iâm trying to use the same procedure i use with the player, aka:
- playerAnimator.SetFloat(âMovementâ, moveDirection.sqrMagnitude);
what should i do, with this code for apply a movement animation?
Posting here to write âThank you so much!â to puppeteer. If anyone is having problems implementing the NPC/enemy wandering system from Rubyâs Adventure (which might be deprecated by now? not sure), this is an amazing solution.
Obviously, make sure your new script is called âWanderer.csâ, otherwise it will get confused. Thanks so much Puppeteer.
Edit:
If anyone reading this thread would like to fix the Y axis movement, and also add animation. Youâll need to make an animator with a state machine set up for directions - you can copy one from the RPG creator kit. You should name the parameters for the state machine âMoveXâ and âMoveYâ. Any issues setting it up, and you can follow the âRubyâs Adventureâ tutorial, under âanimationâ.
This works beginning on an Idle animation, and 4 directional movements.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// This makes an object move randomly in a set of directions, with some random time delay in between each decision
/// </summary>
public class Wanderer : MonoBehaviour
{
internal Transform thisTransform;
public Animator animator;
// The movement speed of the object
public float moveSpeed = 0.2f;
// A minimum and maximum time delay for taking a decision, choosing a direction to move in
public Vector2 decisionTime = new Vector2(1, 4);
internal float decisionTimeCount = 0;
// The possible directions that the object can move int, right, left, up, down, and zero for staying in place. I added zero twice to give a bigger chance if it happening than other directions
internal Vector3[] moveDirections = new Vector3[] { Vector3.right, Vector3.left, Vector3.up, Vector3.down, Vector3.zero, Vector3.zero };
internal int currentMoveDirection;
// Use this for initialization
void Start()
{
// Cache the transform for quicker access
thisTransform = this.transform;
// Set a random time delay for taking a decision ( changing direction,or standing in place for a while )
decisionTimeCount = Random.Range(decisionTime.x, decisionTime.y);
// Choose a movement direction, or stay in place
ChooseMoveDirection();
}
// Update is called once per frame
void Update()
{
// Move the object in the chosen direction at the set speed
Vector3 direction = moveDirections[currentMoveDirection];
float xDir = direction.x;
float yDir = direction.y;
thisTransform.position += direction * Time.deltaTime * moveSpeed;
if (animator)
{
animator.SetFloat("MoveX", xDir);
animator.SetFloat("MoveY", yDir);
}
if (decisionTimeCount > 0) decisionTimeCount -= Time.deltaTime;
else
{
// Choose a random time delay for taking a decision ( changing direction, or standing in place for a while )
decisionTimeCount = Random.Range(decisionTime.x, decisionTime.y);
// Choose a movement direction, or stay in place
ChooseMoveDirection();
}
}
void ChooseMoveDirection()
{
// Choose whether to move sideways or up/down
currentMoveDirection = Mathf.FloorToInt(Random.Range(0, moveDirections.Length));
}
}
Alright, this might be way too late but it may still be useful to some.
So I tried learning this Blend Tree thing and it looks like an awesome way to control animations ( donât know why I never used it before ). Anyway, import this package into your project to see my suggested solution to this wanderer animation.
Basically in the Animator controller we have two floats (âHorizontalâ, âVerticalâ) and they are assigned as a 2D set in the blend tree, and each animation runs based on the directional values I set. Then in the code I call the X and Z values according to âHorizontalâ and âVerticalâ floats, respectively.
It works really nicely, Iâm going to start using this more often.
How would you add idle animation to this code when the NPC stops?
Not sure if this is the right way to do it, but maybe we can check if the player is stopped and then play a random animation from an index, which then goes back to the blend tree.
With this code modification
How to make NPC on stop play IdleAnimation